C #: zapętlanie przez linie ciągu wielowierszowego

100

Jaki jest dobry sposób na zapętlenie każdego wiersza wielowierszowego ciągu bez używania większej ilości pamięci (na przykład bez dzielenia go na tablicę)?

płomienisty
źródło

Odpowiedzi:

158

Sugeruję użycie kombinacji StringReaderi moja LineReaderklasa, która jest częścią MiscUtil, ale jest również dostępna w tej odpowiedzi StackOverflow - możesz łatwo skopiować tylko tę klasę do własnego projektu narzędziowego. Używałbyś tego w ten sposób:

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

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

Zapętlenie nad wszystkie linie w ciele danych String (czy to jest plik lub cokolwiek) jest tak powszechne, że nie powinno wymagać kod wzywający do testowania dla wartości null itp :) Mimo, że jeśli nie chce zrobić pętla ręczna, jest to forma, którą zazwyczaj wolę od Fredrika:

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

W ten sposób wystarczy raz przetestować pod kątem nieważności i nie trzeba też myśleć o pętli do / while (która z jakiegoś powodu zawsze wymaga więcej wysiłku niż przeczytanie prostej pętli while).

Jon Skeet
źródło
74

Możesz użyć a, StringReaderaby odczytać wiersz na raz:

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);
}
Fredrik Mörk
źródło
1
Wspaniały; +1; to pomogło; ale chcę tylko dodać, że tak naprawdę nie trzeba używać bloku „using”, ponieważ w tym przypadku nie ma żadnych zasobów do zamknięcia. Zobacz uwagi w artykule StringReader w docs.microsoft.com
RD Alkire
10

Wiem, że otrzymałem odpowiedź, ale chciałbym dodać własną odpowiedź:

using (var reader = new StringReader(multiLineString))
{
    for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
    {
        // Do something with the line
    }
}
Niels
źródło
7

z MSDN dla 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);
tster
źródło
2

Oto krótki fragment kodu, który znajdzie pierwszą niepustą linię w ciągu:

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 */ }
palswim
źródło
2

Aby zaktualizować to starożytne pytanie dotyczące .NET 4, jest teraz znacznie bardziej przejrzysty sposób:

var lines = File.ReadAllLines(filename);

foreach (string line in lines)
{
    Console.WriteLine(line);
}
NickG
źródło
0

Spróbuj użyć metody String.Split:

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

foreach (string line in text.Split('\n'))
{
    // do something
}
emmediemme82
źródło