将字符串拆分为具有最大长度的行的最佳方法,而不会破坏单词

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)

Eni*_*ity 9

这个解决方案怎么样:

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)


3vt*_*vts 9

即使这篇文章是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


rzs*_*slk 6

我不认为你的解决方案太糟糕了.但是,我确实认为你应该将你的三元分解成一个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.