学习Rx:如何将可观察的字符序列解析为可观察的字符串序列?

时间:2015-05-17 17:12:00

标签: c# system.reactive

这可能非常简单,但我在Rx的学习曲线底部。我花了几个小时阅读文章,观看视频和编写代码,但我似乎对某些看起来应该非常简单的事情存在心理障碍。

我从串口收集数据。我使用Observable.FromEventPattern来捕获SerialDataReceived事件并将其转换为可观察的字符序列。到目前为止一切都很好。

现在,我想根据分隔符来解析该字符序列。没有涉及新行,但每个数据包'数据由前导码和终结符包围,两个都是单个字符。为了论证,我们可以说它们是大括号{}

所以如果我得到了字符序列 j u n k { H e l l o关于我的角色序列的} j u n k, 然后我想在我的字符串序列上发出Hello{Hello}

我可能错过了一些简单的东西,但我甚至无法弄清楚如何处理这个问题。有什么建议吗?

2 个答案:

答案 0 :(得分:6)

使用PublishBuffer

可以轻松完成此操作
var source = "junk{Hello}junk{World}junk".ToObservable();
var messages = source
    .Publish(o =>
    {
        return o.Buffer(
            o.Where(c => c == '{'),
            _ => o.Where(c => c == '}'));
    })
    .Select(buffer => new string(buffer.ToArray()));
messages.Subscribe(x => Console.WriteLine(x));
Console.ReadLine();

这个输出是:

{Hello}
{World}

这个想法是你可以在Buffer的调用中使用以下开始和结束选择器。 Publish的使用是为了确保所有三个Buffer,开场选择器和结束选择器共享相同的订阅。

source:  junk{Hello}junk{World}junk|
opening: ----{----------{----------|
closing:     ------}|
closing:                ------}|

答案 1 :(得分:0)

使用Scan将您迄今收到的值汇总到聚合字符串中(TAccumulatestring),并在每次您将该字符串重置为""时得到一个结束支架。 (我将把实现聚合功能的工作留给你)。这将产生像

这样的可观察量
j
ju
jun
junk
junk{
junk{h
junk{hi
junk{hi}
j
ju
...

然后,您可以使用Where仅发出以}

结尾的内容

然后最后使用Select删除junk

所以完整,应该是

IObservable<string> packetReceived = 
  serialPort.CharReceived
    .Scan(YourAggregationFunction)
    .Where(s => s.EndsWith("}"))
    .Select(s => s.EverythingAfter("{"));

(我将[{1}}留给您实施)。

请注意,在您尝试使用聚合函数时,使用EverythingAfter的{​​{1}}接口来测试它可能更容易,即

IEnumerable

好的,这是一个完整的工作示例

string