Mar*_*arr 11 c# string stringbuilder split
我希望将一个字符串分成指定最大长度的行,如果可能的话,不分割任何单词(如果有一个单词超过最大行长,则必须将其拆分).
与往常一样,我敏锐地意识到字符串是不可变的,并且最好使用StringBuilder类.我已经看过将字符串拆分为单词的示例,然后使用StringBuilder类构建行,但下面的代码对我来说似乎"更整洁".
我在描述中提到"最好"而不是"最有效",因为我也对代码的"口才"感兴趣.字符串永远不会很大,通常会分成2行或3行,并且不会发生数千行.
以下代码真的很糟糕吗?
private static IEnumerable<string> SplitToLines(string stringToSplit, int maximumLineLength)
{
stringToSplit = stringToSplit.Trim();
var lines = new List<string>();
while (stringToSplit.Length > 0)
{
if (stringToSplit.Length <= maximumLineLength)
{
lines.Add(stringToSplit);
break;
}
var indexOfLastSpaceInLine = stringToSplit.Substring(0, maximumLineLength).LastIndexOf(' ');
lines.Add(stringToSplit.Substring(0, indexOfLastSpaceInLine >= 0 ? indexOfLastSpaceInLine : maximumLineLength).Trim());
stringToSplit = stringToSplit.Substring(indexOfLastSpaceInLine >= 0 ? indexOfLastSpaceInLine + 1 : maximumLineLength);
}
return lines.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案怎么样:
IEnumerable<string> SplitToLines(string stringToSplit, int maximumLineLength)
{
var words = stringToSplit.Split(' ').Concat(new [] { "" });
return
words
.Skip(1)
.Aggregate(
words.Take(1).ToList(),
(a, w) =>
{
var last = a.Last();
while (last.Length > maximumLineLength)
{
a[a.Count() - 1] = last.Substring(0, maximumLineLength);
last = last.Substring(maximumLineLength);
a.Add(last);
}
var test = last + " " + w;
if (test.Length > maximumLineLength)
{
a.Add(w);
}
else
{
a[a.Count() - 1] = test;
}
return a;
});
}
Run Code Online (Sandbox Code Playgroud)
即使这篇文章是3年,我想用更好的解决方案Regex来完成相同的工作:
如果您希望拆分字符串然后使用要显示的文本,您可以使用:
public string SplitToLines(string stringToSplit, int maximumLineLength)
{
return Regex.Replace(stringToSplit, @"(.{1," + maximumLineLength +@"})(?:\s|$)", "$1\n");
}
Run Code Online (Sandbox Code Playgroud)
另一方面,如果你需要一个集合,你可以使用它:
public MatchCollection SplitToLines(string stringToSplit, int maximumLineLength)
{
return Regex.Matches(stringToSplit, @"(.{1," + maximumLineLength +@"})(?:\s|$)");
}
Run Code Online (Sandbox Code Playgroud)
该MatchCollection作品几乎像一个Array
我不认为你的解决方案太糟糕了.但是,我确实认为你应该将你的三元分解成一个if else,因为你正在测试两次相同的条件.您的代码也可能有错误.根据您的描述,您似乎想要行<= maxLineLength,但您的代码会计算最后一个单词后面的空格并在<=比较中使用它,从而有效地<修剪字符串的行为.
这是我的解决方案.
private static IEnumerable<string> SplitToLines(string stringToSplit, int maxLineLength)
{
string[] words = stringToSplit.Split(' ');
StringBuilder line = new StringBuilder();
foreach (string word in words)
{
if (word.Length + line.Length <= maxLineLength)
{
line.Append(word + " ");
}
else
{
if (line.Length > 0)
{
yield return line.ToString().Trim();
line.Clear();
}
string overflow = word;
while (overflow.Length > maxLineLength)
{
yield return overflow.Substring(0, maxLineLength);
overflow = overflow.Substring(maxLineLength);
}
line.Append(overflow + " ");
}
}
yield return line.ToString().Trim();
}
Run Code Online (Sandbox Code Playgroud)
它比您的解决方案稍长,但它应该更直接.它还使用StringBuilder,因此对于大字符串来说它要快得多.我对20,000个单词进行了基准测试,范围从1到11个字符,每个字符分成10个字符宽度的行.我的方法在14ms完成,而你的方法为1373ms.