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