使用正则表达式和 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());
}
}
我有一个 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());
}
}