使用正则表达式和 return 匹配值过滤 IObservable<string>

Filter IObservable<string> with regex and return matched value

我有一个 IObservable<string>,我想通过正则表达式将其转换为 IObservable<int>,我可以通过 ToProperty 助手将其分配给 属性。

public class MyViewModel : ReactiveObject
{
    public MyViewModel {
       var o = Observable.Create( .... );

       o.Something(s => .... )  
        .ToProperty(this, x => x.Value, out _Value);    
    }

    private ObservableAsPropertyHelper<int> _value;
    public int Value { get { return _value.value; } }
}

第一题
Something(s => ...) 的最佳替代品是什么?
我想我可以使用 Select(s => s.TryMatchRegex('regex')) where TryMatchRegex returns a int? 然后使用 Where(i => i.HasValue) 然后是新的 Select(i => i.Value) 但我找不到太聪明了...

第二题
现在,假设我有几个正则表达式。每个发布的值都可以匹配零个或多个这些正则表达式。每个正则表达式都有对应的 属性。我需要多次订阅来源,或者有更好的方法吗?

我想你可能想多了。您所建议的一切听起来都很合理,并且首先会导致易于遵循的代码。您可以将正则表达式投影+过滤逻辑包装到具有有意义名称的自定义运算符中,以最大限度地提高可读性。

在优化之前检查性能是否存在问题。明显的优化(如果需要)包括:

  • 如果您不需要了解连续重复输入,请在o上应用DistinctUntilChanged().Publish().RefCount()并订阅你的正则表达式预测
  • Memoize 正则表达式应用程序,具有适当的缓存策略
  • Compile the regexes

SelectMany 查询可能是最好的,因为您可以使用内部 IEnumerable<T> 来表示零个或多个匹配项。

或者,您可以 Publish 使其成为 hot 的来源,这样您就可以为每个 属性 编写单独的查询,而不必担心重复订阅的副作用,除非您打算自己引入并发性以并行执行它们,无论如何,正则表达式将被串行应用;因此,最好将它们组合在一个投影中。

而且我可能只使用在 Rx 中本地定义的 BehaviorSubject<T>。我不太确定 ToProperty 提供了什么。

例如(未测试)

public class MyViewModel
{
  public int X
  {
    get { return x.Value; }
    private set { x.OnNext(value); }
  }

  public int Y
  {
    get { return y.Value; }
    private set { y.OnNext(value); }
  }

  public int Z
  {
    get { return z.Value; }
    private set { z.OnNext(value); }
  }

  private readonly BehaviorSubject<int> x = new BehaviorSubject<int>(0);
  private readonly BehaviorSubject<int> y = new BehaviorSubject<int>(0);
  private readonly BehaviorSubject<int> z = new BehaviorSubject<int>(0);

  public MyViewModel(IObservable<string> source)
  {
    var patterns = new Dictionary<string, IObserver<int>>()
    {
      { patternX, x },
      { patternY, y },
      { patternZ, z }
    };

    (from input in source
     from action in from pattern in patterns
                    let match = Regex.Match(input, pattern.Key)
                    where match.Success
                    let value = GetInt32Somehow(match.Value)
                    select new Action(() => pattern.Value.OnNext(value))
     select action)
     .Subscribe(action => action());
  }
}