【问题标题】:Easiest way to split a string on newlines in .NET?在 .NET 中以换行符分割字符串的最简单方法?
【发布时间】:2009-10-10 09:25:56
【问题描述】:

我需要在 .NET 中将字符串拆分为换行符,而我知道拆分字符串的唯一方法是使用 Split 方法。但是,这不允许我(轻松)在换行符上拆分,那么最好的方法是什么?

【问题讨论】:

  • 为什么不呢?只需拆分 System.Environment.NewLine
  • 但是你必须将它包装在一个字符串[] 中并添加一个额外的参数,然后......它只是感觉很笨重。

标签: c# .net string split


【解决方案1】:

要对字符串进行拆分,您需要使用带有字符串数组的重载:

string[] lines = theText.Split(
    new string[] { Environment.NewLine },
    StringSplitOptions.None
);

编辑:
如果要处理文本中不同类型的换行符,可以使用匹配多个字符串的功能。这将在任何一种换行符上正确拆分,并在文本中保留空行和间距:

string[] lines = theText.Split(
    new string[] { "\r\n", "\r", "\n" },
    StringSplitOptions.None
);

【讨论】:

  • @RCIX:向方法发送正确的参数有点尴尬,因为您将它用于比它所能做的更简单的事情。至少它在那里,在框架 2 之前,您必须使用正则表达式或构建自己的拆分例程来拆分字符串...
  • @Leandro:Environment.NewLine 属性包含系统的默认换行符。例如,对于 Windows 系统,它将是 "\r\n"
  • @Leandro:一种猜测是程序在\n 上拆分,在每一行的末尾留下一个\r,然后在它们之间输出带有\r\n 的行。
  • @Samuel:\r\n 转义序列(以及其他)对 C# 编译器具有特殊意义。 VB 没有这些转义序列,因此使用了这些常量。
  • 如果您想接受来自许多不同操作系统的文件,您还可以在分隔符列表的开头添加“\n\r”,在分隔符列表的末尾添加“\r”。我不确定它是否值得性能打击。 (en.wikipedia.org/wiki/Newline)
【解决方案2】:

使用StringReader 怎么样?

using (System.IO.StringReader reader = new System.IO.StringReader(input)) {
    string line = reader.ReadLine();
}

【讨论】:

  • 这是我的最爱。我包装了一个扩展方法并返回当前行:gist.github.com/ronnieoverby/7916886
  • 这是我为 .netcf 3.5 找到的唯一非正则表达式解决方案
  • 当输入很大并且将其全部复制到数组变得很慢/内存密集时特别好。
  • 如所写,此答案仅读取第一行。请参阅 Steve Cooper's answer 了解应添加到此答案的 while 循环。
  • 字符串为空时不返回一行
【解决方案3】:

你应该可以很容易地分割你的字符串,就像这样:

aString.Split(Environment.NewLine.ToCharArray());

【讨论】:

  • 在非 *nix 系统上,将拆分换行字符串中的单独字符,即 CR 和 LF 字符。这将导致每行之间有一个额外的空字符串。
  • @RCIX:不,\r 和 \n 代码代表单个字符。字符串“\r\n”是两个字符,而不是四个。
  • 如果添加参数StringSplitOptions.RemoveEmptyEntries,那么这将完美地工作。
  • @Ruben:不,不会。 Serge 已经在他的回答中提出了这一点,我已经解释过它还会删除原始文本中应该保留的空行。
  • @Guffa 当然,这假设您实际上想要保留空行。就我而言,我没有,所以这是完美的。但是,是的,如果您试图为用户保留空行数据,那么您将不得不做一些比这更不优雅的事情。
【解决方案4】:

尽量避免使用 string.Split 作为通用解决方案,因为在使用该函数的任何地方都会使用更多内存——原始字符串和拆分副本,两者都在内存中。相信我,当你开始扩展时,这可能是个大问题——运行一个处理 100MB 文档的 32 位批处理应用程序,你会在 8 个并发线程上搞砸。不是说我以前去过那里......

改为使用这样的迭代器;

public static IEnumerable<string> SplitToLines(this string input)
{
    if (input == null)
    {
        yield break;
    }

    using (System.IO.StringReader reader = new System.IO.StringReader(input))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

这将允许您围绕数据进行更高效的内存循环;

foreach(var line in document.SplitToLines()) 
{
    // one line at a time...
}

当然,如果你想全部在内存中,你可以这样做;

var allTheLines = document.SplitToLines().ToArray();

【讨论】:

  • 我去过那里...(解析大型 HTML 文件并耗尽内存)。是的,避免使用 string.Split。使用 string.Split 可能会导致使用 Large Object Heap (LOH) - 但我不能 100% 确定这一点。
【解决方案5】:

根据 Guffa 的回答,在扩展类中使用:

public static string[] Lines(this string source) {
    return source.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
}

【讨论】:

    【解决方案6】:

    对于字符串变量s

    s.Split(new string[]{Environment.NewLine},StringSplitOptions.None)
    

    这将使用您的环境对行尾的定义。在 Windows 上,行结尾是 CR-LF(回车、换行)或 C# 的转义字符 \r\n

    这是一个可靠的解决方案,因为如果你用String.Join 重新组合这些行,这等于你的原始字符串:

    var lines = s.Split(new string[]{Environment.NewLine},StringSplitOptions.None);
    var reconstituted = String.Join(Environment.NewLine,lines);
    Debug.Assert(s==reconstituted);
    

    不该做什么:

    • 使用StringSplitOptions.RemoveEmptyEntries,因为这会破坏 Markdown 等空行具有语法目的的标记。
    • 在分隔符 new char[]{Environment.NewLine} 上拆分,因为在 Windows 上,这将为每一新行创建一个空字符串元素。

    【讨论】:

      【解决方案7】:

      正则表达式也是一种选择:

          private string[] SplitStringByLineFeed(string inpString)
          {
              string[] locResult = Regex.Split(inpString, "[\r\n]+");
              return locResult;
          }
      

      【讨论】:

      • 如果你想精确匹配行,保留空白行,这个正则表达式字符串会更好:"\r?\n"
      【解决方案8】:

      我只是想我会添加我的两位,因为这个问题的其他解决方案不属于可重用代码分类,不方便。

      以下代码块扩展了 string 对象,以便在处理字符串时可以作为自然方法使用。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Collections;
      using System.Collections.ObjectModel;
      
      namespace System
      {
          public static class StringExtensions
          {
              public static string[] Split(this string s, string delimiter, StringSplitOptions options = StringSplitOptions.None)
              {
                  return s.Split(new string[] { delimiter }, options);
              }
          }
      }
      

      您现在可以从任何字符串中使用.Split() 函数,如下所示:

      string[] result;
      
      // Pass a string, and the delimiter
      result = string.Split("My simple string", " ");
      
      // Split an existing string by delimiter only
      string foo = "my - string - i - want - split";
      result = foo.Split("-");
      
      // You can even pass the split options parameter. When omitted it is
      // set to StringSplitOptions.None
      result = foo.Split("-", StringSplitOptions.RemoveEmptyEntries);
      

      要在换行符处拆分,只需将"\n""\r\n" 作为分隔符参数传递。

      评论: 如果微软实现这个重载就好了。

      【讨论】:

      • Environment.Newline 优于硬编码\n\r\n
      • @MichaelBlackburn - 这是一个无效的声明,因为没有上下文。 Environment.Newline 用于跨平台兼容性,不适用于使用与当前操作系统不同的行终止符的文件。 See here for more information,所以这真的取决于开发人员正在使用什么。使用Environment.Newline 可确保操作系统之间的行返回类型没有一致性,其中“硬编码”为开发人员提供了完全控制权。
      • @MichaelBlackburn - 你没必要粗鲁。我只是提供信息。 .Newline 并不神奇,它只是上面提供的字符串,基于它是在 unix 上运行还是在 Windows 上运行的开关。最安全的选择是首先对所有“\r\n”进行字符串替换,然后在“\n”上进行拆分。使用.Newline 失败的地方是当您处理由其他程序保存的文件时,这些程序使用不同的换行方法。如果您知道每次读取的文件总是使用当前操作系统的换行符,那么它会很好地工作。
      • 所以我听到的是最易读的方式(可能是更高的内存使用)是foo = foo.Replace("\r\n", "\n"); string[] result = foo.Split('\n');。我是否正确理解这适用于所有平台?
      【解决方案9】:

      我目前在 VB.NET 中使用此功能(基于其他答案):

      Private Shared Function SplitLines(text As String) As String()
          Return text.Split({Environment.NewLine, vbCrLf, vbLf}, StringSplitOptions.None)
      End Function
      

      它首先尝试在平台本地换行符上拆分,然后回退到每个可能的换行符。

      到目前为止,我只在一个班级内需要这个。如果情况发生变化,我可能会制作这个 Public 并将其移至实用程序类,甚至可能使其成为扩展方法。

      以下是如何将线路连接起来,这是很好的衡量标准:

      Private Shared Function JoinLines(lines As IEnumerable(Of String)) As String
          Return String.Join(Environment.NewLine, lines)
      End Function
      

      【讨论】:

      • @Samuel - 注意引文。他们确实有这个意思。 "\r" = 返回。 "\r\n" = 返回 + 换行。 (请查看这篇文章和accepted solution here
      • @Kraang 嗯.. 我很久没有使用 .NET 了。如果有那么多人投了一个错误的答案,我会感到惊讶。我看到我也评论了 Guffa 的答案,并在那里得到了澄清。我已删除对此答案的评论。感谢您的提醒。
      【解决方案10】:

      好吧,实际上 split 应该这样做:

      //Constructing string...
      StringBuilder sb = new StringBuilder();
      sb.AppendLine("first line");
      sb.AppendLine("second line");
      sb.AppendLine("third line");
      string s = sb.ToString();
      Console.WriteLine(s);
      
      //Splitting multiline string into separate lines
      string[] splitted = s.Split(new string[] {System.Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
      
      // Output (separate lines)
      for( int i = 0; i < splitted.Count(); i++ )
      {
          Console.WriteLine("{0}: {1}", i, splitted[i]);
      }
      

      【讨论】:

      • RemoveEmptyEntries 选项将从文本中删除空行。在某些情况下这可能是可取的,但简单的拆分应该保留空行。
      • 是的,你说得对,我只是做了这个假设,那就是……好吧,空行并不有趣;)
      【解决方案11】:
      string[] lines = text.Split(
        Environment.NewLine.ToCharArray(), 
        StringSplitOptions.RemoveEmptyStrings);
      

      RemoveEmptyStrings 选项将确保您没有空条目,因为 \n 在 \r

      之后

      (编辑以反映 cmets:)请注意,它也会丢弃文本中真正的空行。这通常是我想要的,但可能不是您的要求。

      【讨论】:

      • RemoveEmptyStrings 选项也会删除空行,所以如果文本中有空行,它就不能正常工作。
      • 您可能希望保留真正的空行:\r\n\r\n
      【解决方案12】:

      我不知道 Environment.Newline,但我想这是一个很好的解决方案。

      我的尝试是:

              string str = "Test Me\r\nTest Me\nTest Me";
              var splitted = str.Split('\n').Select(s => s.Trim()).ToArray();
      

      附加的 .Trim 删除可能仍然存在的任何 \r 或 \n (例如,在 Windows 上但使用 os x 换行符拆分字符串时)。不过可能不是最快的方法。

      编辑:

      正如 cmets 正确指出的那样,这也会删除行首或新换行符之前的任何空格。如果您需要保留该空格,请使用其他选项之一。

      【讨论】:

      • Trim 还会删除行首和行尾的任何空白,例如缩进。
      • ".Trim 删除任何可能仍然存在的 \r 或 \n" - 哎哟。为什么不写健壮的代码呢?
      • 也许我的问题弄错了,但是/不清楚必须保留空格。当然你是对的,Trim() 也会删除空格。
      • @Max:哇,等我告诉我的老板,代码可以做任何规范中没有明确排除的事情……;)
      【解决方案13】:

      这里的示例很棒,帮助我应对当前的“挑战”,将 RSA 密钥拆分为更易读的方式。基于Steve Coopers的解决方案:

          string Splitstring(string txt, int n = 120, string AddBefore = "", string AddAfterExtra = "")
          {
              //Spit each string into a n-line length list of strings
              var Lines = Enumerable.Range(0, txt.Length / n).Select(i => txt.Substring(i * n, n)).ToList();
              
              //Check if there are any characters left after split, if so add the rest
              if(txt.Length > ((txt.Length / n)*n) )
                  Lines.Add(txt.Substring((txt.Length/n)*n));
      
              //Create return text, with extras
              string txtReturn = "";
              foreach (string Line in Lines)
                  txtReturn += AddBefore + Line + AddAfterExtra +  Environment.NewLine;
              return txtReturn;
          }
      

      提供一个宽度为 33 个字符的 RSA 密钥,然后简单地使用引号

      Console.WriteLine(Splitstring(RSAPubKey, 33, "\"", "\""));
      

      输出:

      希望有人觉得它有用...

      【讨论】:

        【解决方案14】:

        从 .NET 6 开始,我们可以使用新的 String.ReplaceLineEndings() 方法来规范化跨平台的行尾,所以这些天我发现这是最简单的方法:

        var lines = input
          .ReplaceLineEndings()
          .Split(Environment.NewLine, StringSplitOptions.None);
        

        【讨论】:

          【解决方案15】:

          愚蠢的回答:写入一个临时文件,这样你就可以使用可敬的 File.ReadLines

          var s = "Hello\r\nWorld";
          var path = Path.GetTempFileName();
          using (var writer = new StreamWriter(path))
          {
              writer.Write(s);
          }
          var lines = File.ReadLines(path);
          

          【讨论】:

            【解决方案16】:
            using System.IO;
            
            string textToSplit;
            
            if (textToSplit != null)
            {
                List<string> lines = new List<string>();
                using (StringReader reader = new StringReader(textToSplit))
                {
                    for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
                    {
                        lines.Add(line);
                    }
                }
            }
            

            【讨论】:

              【解决方案17】:

              其实很简单。

              VB.NET:

              Private Function SplitOnNewLine(input as String) As String
                  Return input.Split(Environment.NewLine)
              End Function
              

              C#:

              string splitOnNewLine(string input)
              {
                  return input.split(environment.newline);
              }
              

              【讨论】:

              • 完全不正确并且不起作用。另外,在 C# 中,它是 Environment.NewLine,就像在 VB 中一样。
              • 请参阅 End-of-line identifier in VB.NET? 了解换行的不同选项。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-11-16
              • 1970-01-01
              • 1970-01-01
              • 2022-07-06
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多