在响应式扩展中实现字符串分割()运算符

本文关键字:分割 运算符 字符串 实现 响应 扩展 | 更新日期: 2023-09-27 18:01:58

我希望能够解释输入的字符并"分割"它们(在本例中,通过空格字符)。

var incomingCharacters = "This is a test".ToCharArray().ToObservable();
// Yields a sequence of words - "This", "is", "a", "test"
var incomingWords = incomingCharacters.Split(' ');

我做了一个操作符来做到这一点,但我想知道是否有更好的方法?

public static IObservable<string> Split(this IObservable<char> incomingCharacters, char s)
{
    var wordSeq = Observable.Create<string>(observer =>
        {
            // Create an inner sequence to look for word separators; publish each word to the
            // "outer sequence" as it is found
            var innerSeq = incomingCharacters
                .Concat(Observable.Return(s))           // Enables the last word to be processed
                .Scan(new StringBuilder(), (builder, c) =>
                    {
                        if (c != s)
                        {
                            builder.Append(c);
                            return builder;
                        }
                        // We encountered a "split" character; publish the current completed word
                        // and begin collecting a new one
                        observer.OnNext(builder.ToString());
                        return new StringBuilder();
                    });
            innerSeq.Subscribe(list => { });
            return Disposable.Empty;
    });
    // Return the outer sequence
    return wordSeq;
}

在响应式扩展中实现字符串分割()运算符

有一个更简单的方法来做到这一点,使用Buffer:

public static IObservable<string> Split(
          this IObservable<char> incomingCharacters, 
          char sep)
{
    // Share a single subscription
    var oneSource = incomingCharacters.Publish().RefCount();
    // Our "stop buffering" trigger will be the separators
    var onlySeparators = oneSource
        .Where(c => c == sep);
    return oneSource
        // buffer until we get a separator
        .Buffer(onlySeparators)
        // then return a new string from the buffered chars
        .Select(carr => new string(carr.ToArray()));        
}
测试:

void Main()
{
    var feeder = new Subject<char>();   
    var query = feeder.Split(' ');
    using(query.Subscribe(Console.WriteLine))
    {
        foreach(var c in "this should split words on spaces ".ToCharArray())
        {
            feeder.OnNext(c);
        }
        Console.ReadLine();
    }       
}
输出:

this 
should 
split 
words 
on 
spaces 

编辑:基本的BufferUntil实现

public static class Ext
{
    public static IObservable<IList<T>> BufferUntil<T>(
         this IObservable<T> source, 
         Func<T, bool> predicate)
    {
        var singleSource = source.Publish().RefCount();
        var trigger = singleSource.Where(predicate);
        return singleSource.Buffer(trigger);
    }
    public static IObservable<string> Split(
       this IObservable<char> incomingCharacters, 
       char sep)
    {
        return incomingCharacters
             .BufferUntil(c => c == sep)
             .Select(carr => new string(carr.ToArray()));
    }
}