使用正则表达式过滤IObservable <string>并返回匹配值</string>

时间:2015-01-27 22:03:46

标签: c# system.reactive reactiveui

我想通过正则表达式将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')) TryMatchRegex返回int?,然后使用Where(i => i.HasValue)然后使用新Select(i => i.Value),但我发现它并不聪明。 ..

第二个问题
现在,想象一下我有几个正则表达式。每个发布的值可以匹配这些正则数据中的零个或多个。每个正则表达式都有相应的属性。我需要多次订阅源代码,还是有更好的方法呢?

2 个答案:

答案 0 :(得分:3)

我认为你可能过分思考了。您建议的所有内容听起来都合理,并且会在第一个实例中生成易于遵循的代码。您可以将正则表达式投影+过滤逻辑包装到具有有意义名称的自定义运算符中,以最大限度地提高可读性。

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

  • 如果 您不需要知道连续的重复输入,请在DistinctUntilChanged().Publish().RefCount()上应用o并订阅您的正则表达式投影< / LI>
  • Memoize正则表达式应用程序,具有适当的缓存策略
  • Compile the regexes

答案 1 :(得分:3)

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());
  }
}