C# C中是否有一个懒惰的'String.Split'#

C# C中是否有一个懒惰的'String.Split'#,c#,string,ienumerable,lazy-evaluation,enumerator,C#,String,Ienumerable,Lazy Evaluation,Enumerator,所有方法似乎都返回字符串数组(string[]) 我想知道是否有一个惰性变量返回一个IEnumerable,这样一个用于大字符串(或无限长IEnumerable),当一个人只对第一个子序列感兴趣时,可以节省计算量和内存。如果字符串由设备/程序(网络、终端、管道)构造,并且整个字符串不必立即完全可用,那么它也可能很有用。这样就可以处理第一次发生的事件 在.NET framework中有这样的方法吗?没有内置的方法Regex.Matches是惰性的。也许你可以利用这一点 或者,您只需编写自己的分割函

所有方法似乎都返回字符串数组(
string[]

我想知道是否有一个惰性变量返回一个
IEnumerable
,这样一个用于大字符串(或无限长
IEnumerable
),当一个人只对第一个子序列感兴趣时,可以节省计算量和内存。如果字符串由设备/程序(网络、终端、管道)构造,并且整个字符串不必立即完全可用,那么它也可能很有用。这样就可以处理第一次发生的事件


在.NET framework中有这样的方法吗?

没有内置的方法<如果我正确解释反编译的代码,那么code>Regex.Matches是惰性的。也许你可以利用这一点

或者,您只需编写自己的分割函数


实际上,您可以将大多数
字符串
函数概括为任意序列。通常,甚至是
T
的序列,而不仅仅是
char
。BCL根本没有强调这一点。没有可枚举的
。例如,子序列

没有内置内容,但可以随意删除我的方法:

//
///将字符串拆分为标记。
/// 
///要拆分的字符串。
/// 
///测试代码是否指向某个位置的功能
///输入字符串中有一个分隔符。
/// 
///一系列标记。
IEnumerable标记化(字符串s,Func isSeparator=null)
{
如果(isSeparator==null)isSeparator=(str,i)=>!char.IsleterOrdigit(str,i);
int startPos=-1;
对于(int i=0;i
据我所知,没有内置的方法可以做到这一点。但这并不意味着你不能写。下面是一个示例,让您了解:

public static IEnumerable<string> SplitLazy(this string str, params char[] separators)
{
    List<char> temp = new List<char>();
    foreach (var c in str)
    {
        if (separators.Contains(c) && temp.Any())
        {
             yield return new string(temp.ToArray());
             temp.Clear();
        }
        else
        {
            temp.Add(c);
        }
    }
    if(temp.Any()) { yield return new string(temp.ToArray()); }
}
公共静态IEnumerable SplitLazy(此字符串str,参数char[]分隔符)
{
列表温度=新列表();
foreach(str中的var c)
{
if(分隔符包含(c)和&temp.Any())
{
返回新字符串(temp.ToArray());
温度清除();
}
其他的
{
温度添加(c);
}
}
if(temp.Any()){返回新字符串(temp.ToArray());}
}

当然,这并不能处理所有情况,可以改进。

您可以轻松编写一个:

public static class StringExtensions
{
    public static IEnumerable<string> Split(this string toSplit, params char[] splits)
    {
        if (string.IsNullOrEmpty(toSplit))
            yield break;

        StringBuilder sb = new StringBuilder();

        foreach (var c in toSplit)
        {
            if (splits.Contains(c))
            {
                yield return sb.ToString();
                sb.Clear();
            }
            else
            {
                sb.Append(c);
            }
        }

        if (sb.Length > 0)
            yield return sb.ToString();
    }
}
公共静态类StringExtensions
{
公共静态IEnumerable拆分(此字符串为toSplit,参数为char[]splits)
{
if(string.IsNullOrEmpty(toSplit))
屈服断裂;
StringBuilder sb=新的StringBuilder();
foreach(toSplit中的var c)
{
if(拆分包含(c))
{
让某人返回字符串();
(某人清楚地);
}
其他的
{
sb.附加(c);
}
}
如果(某人长度>0)
让某人返回字符串();
}
}
显然,我还没有用string.split测试它的奇偶校验,但我相信它应该也能正常工作

正如Servy所指出的,这不会在字符串上拆分。这不是那么简单,也不是那么有效,但基本上是相同的模式

public static IEnumerable<string> Split(this string toSplit, string[] separators)
{
    if (string.IsNullOrEmpty(toSplit))
        yield break;

    StringBuilder sb = new StringBuilder();
    foreach (var c in toSplit)
    {
        var s = sb.ToString();
        var sep = separators.FirstOrDefault(i => s.Contains(i));
        if (sep != null)
        {
            yield return s.Replace(sep, string.Empty);
            sb.Clear();
        }
        else
        {
            sb.Append(c);
        }
    }

    if (sb.Length > 0)
        yield return sb.ToString();
}
公共静态IEnumerable拆分(此字符串为拆分,字符串为[]分隔符)
{
if(string.IsNullOrEmpty(toSplit))
屈服断裂;
StringBuilder sb=新的StringBuilder();
foreach(toSplit中的var c)
{
var s=sb.ToString();
var sep=分隔符.FirstOrDefault(i=>s.Contains(i));
如果(sep!=null)
{
收益率返回s.Replace(sep,string.Empty);
(某人清楚地);
}
其他的
{
sb.附加(c);
}
}
如果(某人长度>0)
让某人返回字符串();
}

我编写了这个变体,它还支持SplitOptions和count。 它的行为类似于string.Split,在我尝试的所有测试用例中都是如此。 操作员的名称为C#6 sepcific,可替换为“count”

公共静态类StringExtensions
{
/// 
///将字符串拆分为基于数组中字符的子字符串。
/// 
///要拆分的字符串。
///从返回的数组中省略空数组元素;或在返回的数组中包含空数组元素。
///要返回的子字符串的最大数目。
///分隔此字符串中的子字符串的字符数组、不包含分隔符的空数组或null。
/// 
/// 
///分隔符字符不包括在返回数组的元素中。
///如果此实例不包含分隔符中的任何字符,则返回的序列由包含此实例的单个元素组成。
///如果separator参数为null或不包含任何字符,则假定空白字符为分隔符。空白字符由Unicode标准定义,如果传递给方法,则返回true。
/// 
公共静态IEnumerable SplitLazy(此字符串值,int count=int.MaxValue,StringSplitOptions=StringSplitOptions.None,params char[]分隔符)
{
if(计数分隔符)包含(c);
if(string.IsNullOrEmpty(value)| | count==1 | |!value.Any(谓词))
{
收益回报值;
屈服断裂;
}
boolRemoveEmptyEntries=(选项和StringSplitOptions.removeEmptyEntries)!=0;
int-ct=0;
var sb=新的StringBuilder();
对于(int i=0;ipublic static IEnumerable<string> Split(this string toSplit, string[] separators)
{
    if (string.IsNullOrEmpty(toSplit))
        yield break;

    StringBuilder sb = new StringBuilder();
    foreach (var c in toSplit)
    {
        var s = sb.ToString();
        var sep = separators.FirstOrDefault(i => s.Contains(i));
        if (sep != null)
        {
            yield return s.Replace(sep, string.Empty);
            sb.Clear();
        }
        else
        {
            sb.Append(c);
        }
    }

    if (sb.Length > 0)
        yield return sb.ToString();
}
public static class StringExtensions
{
    /// <summary>
    /// Splits a string into substrings that are based on the characters in an array. 
    /// </summary>
    /// <param name="value">The string to split.</param>
    /// <param name="options"><see cref="StringSplitOptions.RemoveEmptyEntries"/> to omit empty array elements from the array returned; or <see cref="StringSplitOptions.None"/> to include empty array elements in the array returned.</param>
    /// <param name="count">The maximum number of substrings to return.</param>
    /// <param name="separator">A character array that delimits the substrings in this string, an empty array that contains no delimiters, or null. </param>
    /// <returns></returns>
    /// <remarks>
    /// Delimiter characters are not included in the elements of the returned array. 
    /// If this instance does not contain any of the characters in separator the returned sequence consists of a single element that contains this instance.
    /// If the separator parameter is null or contains no characters, white-space characters are assumed to be the delimiters. White-space characters are defined by the Unicode standard and return true if they are passed to the <see cref="Char.IsWhiteSpace"/> method.
    /// </remarks>
    public static IEnumerable<string> SplitLazy(this string value, int count = int.MaxValue, StringSplitOptions options = StringSplitOptions.None, params char[] separator)
    {
        if (count <= 0)
        {
            if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Count cannot be less than zero.");
            yield break;
        }

        Func<char, bool> predicate = char.IsWhiteSpace;
        if (separator != null && separator.Length != 0)
            predicate = (c) => separator.Contains(c);

        if (string.IsNullOrEmpty(value) || count == 1 || !value.Any(predicate))
        {
            yield return value;
            yield break;
        }

        bool removeEmptyEntries = (options & StringSplitOptions.RemoveEmptyEntries) != 0;
        int ct = 0;
        var sb = new StringBuilder();
        for (int i = 0; i < value.Length; ++i)
        {
            char c = value[i];
            if (!predicate(c))
            {
                sb.Append(c);
            }
            else
            {
                if (sb.Length != 0)
                {
                    yield return sb.ToString();
                    sb.Clear();
                }
                else
                {
                    if (removeEmptyEntries)
                        continue;
                    yield return string.Empty;
                }

                if (++ct >= count - 1)
                {
                    if (removeEmptyEntries)
                        while (++i < value.Length && predicate(value[i]));
                    else
                        ++i;
                    if (i < value.Length - 1)
                    {
                        sb.Append(value, i, value.Length - i);
                        yield return sb.ToString();
                    }
                    yield break;
                }
            }
        }

        if (sb.Length > 0)
            yield return sb.ToString();
        else if (!removeEmptyEntries && predicate(value[value.Length - 1]))
            yield return string.Empty;
    }

    public static IEnumerable<string> SplitLazy(this string value, params char[] separator)
    {
        return value.SplitLazy(int.MaxValue, StringSplitOptions.None, separator);
    }

    public static IEnumerable<string> SplitLazy(this string value, StringSplitOptions options, params char[] separator)
    {
        return value.SplitLazy(int.MaxValue, options, separator);
    }

    public static IEnumerable<string> SplitLazy(this string value, int count, params char[] separator)
    {
        return value.SplitLazy(count, StringSplitOptions.None, separator);
    }
}
public static IEnumerable<string> Split(string input, string pattern, RegexOptions options = RegexOptions.None)
{
    // Always compile - we expect many executions
    var regex = new Regex(pattern, options | RegexOptions.Compiled);

    int currentSplitStart = 0;
    var match = regex.Match(input);

    while (match.Success)
    {
        yield return input.Substring(currentSplitStart, match.Index - currentSplitStart);

        currentSplitStart = match.Index + match.Length;
        match = match.NextMatch();
    }

    yield return input.Substring(currentSplitStart);
}
public static IEnumerable<string> LazySplit(this string source, StringSplitOptions stringSplitOptions, params string[] separators)
{
    var sourceLen = source.Length;

    bool IsSeparator(int index, string separator)
    {
        var separatorLen = separator.Length;

        if (sourceLen < index + separatorLen)
        {
            return false;
        }

        for (var i = 0; i < separatorLen; i++)
        {
            if (source[index + i] != separator[i])
            {
                return false;
            }
        }

        return true;
    }

    var indexOfStartChunk = 0;

    for (var i = 0; i < source.Length; i++)
    {
        foreach (var separator in separators)
        {
            if (IsSeparator(i, separator))
            {
                if (indexOfStartChunk == i && stringSplitOptions != StringSplitOptions.RemoveEmptyEntries)
                {
                    yield return string.Empty;
                }
                else
                {
                    yield return source.Substring(indexOfStartChunk, i - indexOfStartChunk);
                }

                i += separator.Length;
                indexOfStartChunk = i--;
                break;
            }
        }
    }

    if (indexOfStartChunk != 0)
    {
        yield return source.Substring(indexOfStartChunk, sourceLen - indexOfStartChunk);
    }
}