如何获取 StringBuilder 的行数?

38

我有一个 StringBuilder 实例,我在里面做了很多类似 sb.AppendLine("test"); 的操作。

如何计算我有多少行?

我看到这个类有 .Length, 但那只告诉我所有字符的数量。

有什么想法吗?


你有没有考虑过计算换行符的数量? - Adrian Grigore
计算换行符的唯一问题是 StringBuilder 没有查找/索引方法 - 你需要使用 Chars 索引属性或在结果字符串 (ToString()) 中进行计数。如果您需要重复计算行数,这两种方法都可能效率低下。 - VinayC
1
Jon,有很多非常明显的解决方案;你能否提供上下文来解释为什么这些解决方案对你不可行? - tenfour
我只需要它一次。但是我也意识到我需要在某个特定的位置插入一行代码,但不知道应该在哪里插入。 - Jon
我喜欢一些更基础的问题在SO上产生了很多反馈的方式。惊人的是你可以学到并在其他地方使用的小贴士。 - Paul Hadfield
由于这个老问题没有提供真正好的解决方案,我会提供我刚使用的方法(放弃了我之前使用的StringBuilder):List<string> text = new List<string>(); - Jon Harbour
10个回答

32

按效率排序:

  1. 计数 AppendLine() 调用次数
  2. 在循环中调用 IndexOf()
  3. 使用正则表达式
  4. 使用 String.Split()

最后一个非常昂贵且会生成大量垃圾,请勿使用。


11
我认为选项#1可能会导致错误,因为它不能保证计算的AppendLine()调用次数与实际换行符的数量完全一致。其他选项则很有道理。 - code4life
2
嗯,换行符并不会从天上掉下来。但是是的,在这里追求效率可能会牺牲可维护性。 - Hans Passant
12
它们可能不会从天上掉下来,但它们可以来自于 Environment.NewLine\r\n\n,甚至是传递给其他方法的内容。 - Matthew Whited

27

你可以使用自己的类将StringBuilder进行包装,以便在添加行时保持计数或者在builder满后统计 '\n' 的数量。

Regex.Matches(builder.ToString(), Environment.NewLine).Count

5
我猜你的意思是 Regex.Matches(builder.ToString(), Environment.NewLine).Count;,因为Match()只返回一个匹配。 - alex440

6
您可以创建一个包装类来执行以下操作:
public class Wrapper
{
    private StringBuilder strBuild = null;
    private int count = 0;
    public Wrapper(){
        strBuild = new StringBuilder();
    }
    public void AppendLine(String toAppendParam){
        strBuild.AppendLine(toAppendParam);
        count++;
    }
    public StringBuilder getStringBuilder(){
        return strBuild;
    }

    public int getCount(){
        return count;
    }
}

3
我已为您修复了代码格式,但您可能希望将其改得更符合C#语言的惯用方式,而不是Java。 - user7116

3

试试这个:

sb.ToString().Split(System.Environment.NewLine.ToCharArray()).Length;

2
这段代码会重复计算行数...例如,sb.AppendLine("a"); 这个语句的3行将导致结果为7而不是3...! - code4life
@code4life 是的(当然这取决于所涉及系统中 NewLine 字符串的长度)。 - Jeppe Stig Nielsen
这将不计算行数,但会计算换行符的使用。对于Linux来说这是有效的,但Windows使用\r\n。如果这个答案应该在所有机器上真正计算行数,只需删除.ToCharArray()即可。 - Jack Miller

2

更新 Gabe所说的话

b.ToString().Count(c => c =='\n') 这里也可以工作,而且效率可能不会比从 StringBuilder 创建一个单独的字符串并分割或创建字符串和正则表达式更低!


有一种更好的方法,比从 StringBuilder 创建字符串并分离它(或创建字符串并使用正则表达式)更快,即查看 StringBuilder 并计算其中的 '\n' 字符数。

下面这个扩展方法将枚举字符串生成器中的字符,您可以使用 Linq 对其进行操作。

    public static IEnumerable<char> GetEnumerator(this StringBuilder sb)
    {
        for (int i = 0; i < sb.Length; i++)
            yield return sb[i];
    }

...在这里使用,计数将为4

        StringBuilder b = new StringBuilder();
        b.AppendLine("Hello\n");
        b.AppendLine("World\n");

        int lineCount = b.GetEnumerator().Count(c => c =='\n');


b.ToString().Count(c => c =='\n') 在这里也可以工作,并且可能不会比较低效(除了创建一个单独的字符串副本之外!)。 - Gabe
@Gabe:我应该知道 b.ToString().Count(c => c =='\n') 的时间只需要我的枚举器的2/3。 - Binary Worrier

2
如果您打算使用String.Split(),则需要使用一些选项来拆分字符串。像这样:
static void Main(string[] args)
{
    var sb = new StringBuilder();
    sb.AppendLine("this");
    sb.AppendLine("is");
    sb.AppendLine("a");
    sb.AppendLine("test");

    // StringSplitOptions.None counts the last (blank) newline 
    // which the last AppendLine call creates
    // if you don't want this, then replace with 
    // StringSplitOptions.RemoveEmptyEntries
    var lines = sb.ToString().Split(
        new string[] { 
            System.Environment.NewLine }, 
        StringSplitOptions.None).Length;

    Console.WriteLine("Number of lines: " + lines);

    Console.WriteLine("Press enter to exit.");
    Console.ReadLine();
}

这将导致以下结果:

行数:5


2

您应该能够搜索字符串中 \n 的出现次数。

更新: 一种方法是在换行符上进行拆分,并按以下方式计算数组中的元素数量:

sb.ToString().Split('\n').length;

肯定会起作用,但如果您需要重复计算行数,则不是一个好的解决方案。当然,Jon还没有提到他想要一次还是多次。 - VinayC
@VninayC - 是的,这只是我脑海中的一个想法,我一开始就不喜欢它,因为你必须要做一个ToString()才能做任何事情。如果你想多次执行它,把它包装在一个自己保持计数的东西里肯定是最好的选择。 - Paul Hadfield

1

衍生自己的行计数 StringBuilder,其中 AppendLine 增加内部行计数并提供获取行计数值的方法。


0

使用正则表达式来计算字符串中行终止符(例如:\r\n)的数量。或者,将字符串加载到文本框中并进行行计数,但这是一种不太优雅的方法。


0
你可以将字符串构建器数据拆分为String[]数组,然后使用String[].Length获取行数。
类似下面这样的操作:
String[] linestext = sb.Split(newline)
Console.Writeline(linetext.Length)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接