【问题标题】:How to count lines in a string?如何计算字符串中的行数?
【发布时间】:2012-06-26 16:59:56
【问题描述】:

我正在从字符串中删除文本以及用空行替换每一行的内容。

一些背景: 我正在编写一个比较两个字符串的比较函数。它一切正常,并显示在两个单独的网络浏览器中。当我尝试在浏览器上向下滚动时,字符串的长度不同,我想用空行替换要删除的文本,以便我的字符串长度相同。

在下面的代码中,我希望计算 aDiff.Text 有多少行

这是我的代码:

public string diff_prettyHtmlShowInserts(List<Diff> diffs)
    {
        StringBuilder html = new StringBuilder();

        foreach (Diff aDiff in diffs)
        {
            string text = aDiff.text.Replace("&", "&amp;").Replace("<", "&lt;")
              .Replace(">", "&gt;").Replace("\n", "<br>"); //&para;
            switch (aDiff.operation)
            {

                case Operation.DELETE:                              
                   //foreach('\n' in aDiff.text)
                   // {
                   //     html.Append("\n"); // Would like to replace each line with a blankline
                   // }
                    break;
                case Operation.EQUAL:
                    html.Append("<span>").Append(text).Append("</span>");
                    break;
                case Operation.INSERT:
                    html.Append("<ins style=\"background:#e6ffe6;\">").Append(text)
                        .Append("</ins>");
                    break;
            }
        }
        return html.ToString();
    }

【问题讨论】:

  • 这行得通,但我需要为每个旧行创建一个新行,以便为可能是 8 行的整个字符串创建一个新行

标签: c#


【解决方案1】:

方法一:

int numLines = aDiff.text.Length - aDiff.text.Replace _
                   (Environment.NewLine, string.Empty).Length;

方法二:

int numLines = aDiff.text.Split('\n').Length;

两者都会给你文本的行数。

【讨论】:

  • 谢谢让我看看:D
  • 'string.Split(params char[])' 的最佳重载方法匹配有一些无效参数是我收到的错误
  • 抱歉还不能投票,需要更高的代表,但感谢您的帮助:)
  • 请注意,就性能而言,拆分字符串将分配空间来创建数组,以便它可以计算数组中的最终元素数。这是非常低效的,如果你在足够大的输入文本上运行它,它实际上会生成 OutOfMemoryExceptions。 @GrahamBedford Answer 下面是最正确的。
  • @Casey 这个答案包括两个选项,其中一个与格雷厄姆的解决方案相同。但它仍然分配内存(text.Replace 将分配)
【解决方案2】:

不分配新字符串或字符串数​​组的变体

private static int CountLines(string str)
{
    if (str == null)
        throw new ArgumentNullException("str");
    if (str == string.Empty)
        return 0;
    int index = -1;
    int count = 0;
    while (-1 != (index = str.IndexOf(Environment.NewLine, index + 1)))
        count++;

   return count + 1;
}

【讨论】:

    【解决方案3】:

    您还可以使用 Linq 来计算行的出现次数,如下所示:

    int numLines = aDiff.Count(c => c.Equals('\n')) + 1;
    

    迟到了,但提供了其他答案的替代方案。

    【讨论】:

    • 这里只回答不创建新的不必要的对象
    【解决方案4】:

    效率低,但仍然:

    var newLineCount = aDiff.Text.Split('\n').Length -1;
    

    【讨论】:

    • 它甚至无法编译! var newLineCount = aDiff.Text.Split(new string[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries).Length;
    • 只需使用换行符\n
    • 对不起,你是对的,它可以编译。然而 Environment.NewLine 转换为运行应用程序的平台的正确换行符:msdn.microsoft.com/it-it/library/…
    【解决方案5】:

    我对不同的方法(Split、Replace、for loop over chars、Linq.Count)进行了一系列性能测试,获胜者是 Replace 方法(当字符串小于 2KB 时,Split 方法稍快,但不多)。

    但接受的答案中有 2 个错误。一个错误是当最后一行没有以换行符结尾时,它不会计算最后一行。另一个错误是,如果您在 Windows 上读取具有 UNIX 行结尾的文件,则不会计算任何行,因为 Environment.Newline 是 \r\n 并且不存在(您始终可以只使用 \n,因为它是最后一个UNIX 和 Windows 的行尾字符)。

    所以这里有一个简单的扩展方法...

    public static int CountLines(this string text)
    {
        int count = 0;
        if (!string.IsNullOrEmpty(text))
        {
            count = text.Length - text.Replace("\n", string.Empty).Length;
    
            // if the last char of the string is not a newline, make sure to count that line too
            if (text[text.Length - 1] != '\n')
            {
                ++count;
            }
        }
    
        return count;
    }
    

    【讨论】:

    • 好吧,如果性能结果正确,我认为这应该被接受。但我仍然不明白通过字符串的单循环如何变慢,我几乎可以肯定使用不安全的代码会更快
    【解决方案6】:
    int newLineLen = Environment.NewLine.Length;
    int numLines = aDiff.text.Length - aDiff.text.Replace(Environment.NewLine, string.Empty).Length;
    if (newLineLen != 0)
    {
        numLines /= newLineLen;
        numLines++;
    }
    

    稍微更健壮,考虑到第一行不会有换行符。

    【讨论】:

    • 为什么(何时)Environment.NewLine.Length 会返回零?来自msdn.microsoft.com/en-us/library/… 的引用:非 Unix 平台包含“\r\n”的字符串,或 Unix 平台包含“\n”的字符串。
    • 我不知道为什么它的长度为零。但是当我除以我不是绝对 100% 不会为零的东西时,我无论如何都会检查。但是是的,您是对的,因为它在当前支持的平台上不应该为零。
    【解决方案7】:

    为了方便起见,我将poncha 的解决方案放在了一个很好的扩展方法中,所以你可以像这样简单地使用它:

    int numLines = aDiff.text.LineCount();
    

    代码:

    /// <summary>
    /// Extension class for strings.
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// Get the nummer of lines in the string.
        /// </summary>
        /// <returns>Nummer of lines</returns>
        public static int LineCount(this string str)
        {
            return str.Split('\n').Length;
        }
    }
    

    玩得开心……

    【讨论】:

      【解决方案8】:
      using System.Text.RegularExpressions;
      
      Regex.Matches(text, "\n").Count
      

      考虑到速度和内存使用情况,我认为计算'\n' 的出现是最有效的方法。

      使用split('\n') 是个坏主意,因为它会生成新的字符串数组,因此性能和效率都很差!特别是当您的字符串变大并包含更多行时。

      用空字符替换'\n'字符并计算差异也不是很有效,因为它应该做一些操作,如搜索、创建新字符串和内存分配等。

      您可以只执行一项操作,即搜索。因此,您可以按照@lokimidgard 的建议计算字符串中'\n' 字符的出现次数。

      值得一提的是,搜索'\n' 字符比搜索"\r\n"(或Windows 中的Environment.NewLine)要好,因为前者(即'\n')适用于Unix 和Windows 行尾。

      【讨论】:

        【解决方案9】:

        高效且成本最低的内存。

        Regex.Matches( "Your String" , System.Environment.NewLine).Count ;
        

        当然,我们可以扩展我们的字符串类

        using System.Text.RegularExpressions ;
        
        public static class StringExtensions
        {
            /// <summary>
            /// Get the nummer of lines in the string.
            /// </summary>
            /// <returns>Nummer of lines</returns>
            public static int LineCount(this string str)
            {
                return Regex.Matches( str , System.Environment.NewLine).Count ;
            }
        }
        

        参考:µBioDieter Meemken

        【讨论】:

        • 如果最后一行没有'\r\n'则不计算最后一行
        • 就像@muh 说的,Count 后面应该有一个+ 1。否则,例如,单个行字符串的行数不会为 1。
        【解决方案10】:

        在这里聚会迟到了,但我认为这可以处理所有行,甚至最后一行(至少在 Windows 上):

        Regex.Matches(text, "$", RegexOptions.Multiline).Count; 
        

        【讨论】:

          【解决方案11】:
          public static int CalcStringLines(string text)
          {
              int count = 1;
              for (int i = 0; i < text.Length; i++)
              {
                  if (text[i] == '\n') count++;
              }
          
              return count;
          }
          

          这是最快/最简单/无内存分配的方式...

          【讨论】:

            猜你喜欢
            • 2012-01-19
            • 1970-01-01
            • 2021-10-25
            • 1970-01-01
            • 1970-01-01
            • 2020-03-12
            • 2011-02-20
            • 2010-11-08
            • 2022-12-21
            相关资源
            最近更新 更多