C#: 循环遍历多行字符串的每一行

115

如何循环遍历多行字符串中的每一行,而不使用更多内存(例如不将其拆分为数组)?

8个回答

177

我建议使用StringReader和我的LineReader类的组合,LineReader类是MiscUtil中的一部分,但也可以在这个StackOverflow答案中找到 - 您可以轻松地将该类复制到您自己的实用程序项目中。您可以像这样使用它:

string text = @"First line
second line
third line";

foreach (string line in new LineReader(() => new StringReader(text)))
{
    Console.WriteLine(line);
}

在字符串数据(无论是文件还是其他形式)中循环遍历所有行如此常见,以至于不应要求调用代码进行null等测试 :) 话虽如此,如果您确实想要手动进行循环,这是我通常比Fredrik更喜欢的形式:

using (StringReader reader = new StringReader(input))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        // Do something with the line
    }
}

这样您只需测试一次是否为 null,而且也不必考虑 do/while 循环(相比起直接的 while 循环,读起来总是需要更多的精力)。


看起来 MiscUtil 没有 .NET Core 的版本。 - void.pointer
@void.pointer:不好意思,它并没有。这不是我在过去10年里花时间投入的一个项目。 - Jon Skeet
StringReader,一个不太为人知的对象。谢谢。这正是我需要的。 - RogerEdward

85

您可以使用StringReader以逐行读取的方式来处理字符串:

using (StringReader reader = new StringReader(input))
{
    string line = string.Empty;
    do
    {
        line = reader.ReadLine();
        if (line != null)
        {
            // do something with the line
        }

    } while (line != null);
}

3
好的,我会尽力进行翻译。以下是需要翻译的内容:Great; +1; this helped; but I just want to add that one does not actually need to use the "using" block because there aren't any resources to close in this case. See remarks in StringReader article at learn.microsoft.com非常好;点赞;这有帮助;但我只想补充说,在这种情况下实际上不需要使用“using”块,因为没有资源需要关闭。请参见在learn.microsoft.com上StringReader文章中的注释 - R.D. Alkire

26

我知道这个问题已经有答案了,但是我想加上我的答案:

using (var reader = new StringReader(multiLineString))
{
    for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
    {
        // Do something with the line
    }
}

我喜欢这个的简洁性。谢谢。 - CANDIMAN

9

from MSDN for StringReader

    string textReaderText = "TextReader is the abstract base " +
        "class of StreamReader and StringReader, which read " +
        "characters from streams and strings, respectively.\n\n" +

        "Create an instance of TextReader to open a text file " +
        "for reading a specified range of characters, or to " +
        "create a reader based on an existing stream.\n\n" +

        "You can also use an instance of TextReader to read " +
        "text from a custom backing store using the same " +
        "APIs you would use for a string or a stream.\n\n";

    Console.WriteLine("Original text:\n\n{0}", textReaderText);

    // From textReaderText, create a continuous paragraph 
    // with two spaces between each sentence.
    string aLine, aParagraph = null;
    StringReader strReader = new StringReader(textReaderText);
    while(true)
    {
        aLine = strReader.ReadLine();
        if(aLine != null)
        {
            aParagraph = aParagraph + aLine + " ";
        }
        else
        {
            aParagraph = aParagraph + "\n";
            break;
        }
    }
    Console.WriteLine("Modified text:\n\n{0}", aParagraph);

3
尝试使用 String.Split 方法:
string text = @"First line
second line
third line";

foreach (string line in text.Split('\n'))
{
    // do something
}

2
这是一个快速的代码片段,用于查找字符串中第一行非空的内容:
string line1;
while (
    ((line1 = sr.ReadLine()) != null) &&
    ((line1 = line1.Trim()).Length == 0)
)
{ /* Do nothing - just trying to find first non-empty line*/ }

if(line1 == null){ /* Error - no non-empty lines in string */ }

1
有时候,我们可能会过度复杂化解决方案,只是为了避免重复一行代码。这就是我首先想到这个问题的原因。
经过一番思考,我得出的结论是最简单的解决方案是在循环之前和循环内部重复使用ReadLine
using (var stringReader = new StringReader(input))
{
    var line = await stringReader.ReadLineAsync();

    while (line != null)
    {
        // do something
        line = await stringReader.ReadLineAsync();
    }
}

我知道这可能被认为不符合DRY原则,但考虑到它的简单性,我认为值得考虑。


0
你可以使用扩展方法:
public static IEnumerable<string> EnumerateLines(this string source)
{
  ArgumentNullException.ThrowIfNull(source);

  using StringReader reader = new StringReader(source);

  while(reader.ReadLine() is { } line)
  {
    yield return line;
  }
}

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