Wenn es hässlich aussieht, entfernen Sie einfach den unnötigen ToCharArrayAnruf.
Wenn Sie entweder \noder teilen möchten \r, haben Sie zwei Möglichkeiten:
Verwenden Sie ein Array-Literal. Dadurch erhalten Sie jedoch leere Zeilen für Zeilenenden im Windows-Stil \r\n:
var result = text.Split(new[]{'\r','\n'});
Verwenden Sie einen regulären Ausdruck, wie von Bart angegeben:
var result =Regex.Split(text,"\r\n|\r|\n");
Wenn Sie leere Zeilen beibehalten möchten, warum weisen Sie C # ausdrücklich an, sie wegzuwerfen? ( StringSplitOptionsParameter) - StringSplitOptions.Nonestattdessen verwenden.
Durch das Entfernen von ToCharArray wird der Code plattformspezifisch (NewLine kann '\ n' sein)
Konstantin Spirin
1
@Will: auf gut Glück , dass Sie anstelle von Konstantin mir bezogen sich : I (glauben stark ) , dass Code Parsen auf allen Plattformen zur Arbeit anstreben sollten (dh es sollte auch Textdateien lesen , die auf codiert wurden verschiedene Plattformen als die Ausführung Plattform ). Für das Parsen Environment.NewLineist es für mich ein No-Go. Tatsächlich bevorzuge ich von allen möglichen Lösungen die mit regulären Ausdrücken, da nur diese alle Quellplattformen korrekt handhabt.
Konrad Rudolph
2
@ Hamish Nun, schauen Sie sich einfach die Dokumentation der Aufzählung an oder schauen Sie in die ursprüngliche Frage! Es ist StringSplitOptions.RemoveEmptyEntries.
Konrad Rudolph
8
Wie wäre es mit dem Text, der '\ r \ n \ r \ n' enthält. string.Split gibt 4 leere Zeilen zurück, sollte jedoch mit '\ r \ n' 2 ergeben. Es wird schlimmer, wenn '\ r \ n' und '\ r' in einer Datei gemischt werden.
Benutzername
1
@SurikovPavel Verwenden Sie den regulären Ausdruck. Dies ist definitiv die bevorzugte Variante, da sie mit jeder Kombination von Zeilenenden korrekt funktioniert.
Konrad Rudolph
134
using (StringReader sr =newStringReader(text)){string line;while((line = sr.ReadLine())!=null){// do something}}
Es ist wichtig, "\r\n"zuerst im Array zu haben, damit es als ein Zeilenumbruch genommen wird. Das Obige ergibt die gleichen Ergebnisse wie jede dieser Regex-Lösungen:
Bitte fügen Sie einige weitere Details hinzu, um Ihre Antwort für die Leser nützlicher zu machen.
Mohit Jain
Getan. Außerdem wurde ein Test hinzugefügt, um die Leistung mit der Regex-Lösung zu vergleichen.
Orad
Etwas schnelleres Muster aufgrund weniger Backtracking mit der gleichen Funktionalität, wenn man verwendet[\r\n]{1,2}
ΩmegaMan
@OmegaMan Das hat ein anderes Verhalten. Es wird übereinstimmen \n\roder \n\nals einzelner Zeilenumbruch, was nicht korrekt ist.
Orad
3
@OmegaMan Wie ist Hello\n\nworld\n\nein Edge Case? Es ist eindeutig eine Zeile mit Text, gefolgt von einer leeren Zeile, gefolgt von einer weiteren Zeile mit Text, gefolgt von einer leeren Zeile.
Brandin
36
Sie könnten Regex.Split verwenden:
string[] tokens =Regex.Split(input,@"\r?\n|\r");
Bearbeiten: hinzugefügt |\r, um (ältere) Mac-Leitungsabschlüsse zu berücksichtigen.
Dies funktioniert jedoch nicht bei Textdateien im OS X-Stil, da diese nur \rals Zeilenende verwendet werden.
Konrad Rudolph
2
@Konrad Rudolph: AFAIK, '\ r' wurde auf sehr alten MacOS-Systemen verwendet und ist fast nie mehr anzutreffen. Aber wenn das OP dies berücksichtigen muss (oder wenn ich mich irre), kann der reguläre Ausdruck natürlich leicht erweitert werden, um dies zu berücksichtigen: \ r? \ N | \ r
Bart Kiers
@Bart: Ich glaube nicht, dass Sie sich irren, aber ich bin in meiner Karriere als Programmierer wiederholt auf alle möglichen Zeilenenden gestoßen.
Konrad Rudolph
@Konrad, du hast wahrscheinlich recht. Besser sicher als leid, denke ich.
Bart Kiers
1
@ ΩmegaMan: Das verliert leere Zeilen, zB \ n \ n.
Mike Rosoft
9
Wenn Sie leere Zeilen behalten möchten, entfernen Sie einfach die StringSplitOptions.
var result = input.Split(System.Environment.NewLine.ToCharArray());
NewLine kann '\ n' sein und der eingegebene Text kann "\ n \ r" enthalten.
Konstantin Spirin
4
Ich hatte diese andere Antwort, aber diese, basierend auf Jacks Antwort , ist deutlich schneller und wird möglicherweise bevorzugt, da sie asynchron arbeitet, obwohl sie etwas langsamer ist.
publicstaticclassStringExtensionMethods{publicstaticIEnumerable<string>GetLines(thisstring str,bool removeEmptyLines =false){
using (var sr =newStringReader(str)){string line;while((line = sr.ReadLine())!=null){if(removeEmptyLines &&String.IsNullOrWhiteSpace(line)){continue;}yieldreturn line;}}}}
Ich frage mich, ob dies daran liegt, dass Sie die Ergebnisse des Enumerators nicht tatsächlich überprüfen und er daher nicht ausgeführt wird. Leider bin ich zu faul, um das zu überprüfen.
James Holwell
Ja, das ist es tatsächlich !! Wenn Sie beiden Aufrufen .ToList () hinzufügen, ist die StringReader-Lösung tatsächlich langsamer! Auf meinem Computer ist es 6.74s vs. 5.10s
JCH2k
Das macht Sinn. Ich bevorzuge diese Methode immer noch, weil ich damit Linien asynchron abrufen kann.
Orad
Vielleicht sollten Sie den Header "Bessere Lösung" in Ihrer anderen Antwort entfernen und diese bearbeiten ...
Es ist schwierig, gemischte Zeilenenden richtig zu handhaben . Wie wir wissen, können die Leitungsabschluss Zeichen "Line Feed" (ASCII 10, \n, \x0A, \u000A), "Carriage Return" (ASCII 13 \r, \x0D, \u000D) oder eine Kombination von ihnen. Zurück zu DOS verwendet Windows die zweistellige Sequenz CR-LF \u000D\u000A, daher sollte diese Kombination nur eine einzige Zeile ausgeben. Unix verwendet ein einzelnes \u000Aund sehr alte Macs verwenden ein einzelnes \u000DZeichen. Die Standardmethode zum Behandeln beliebiger Mischungen dieser Zeichen in einer einzelnen Textdatei lautet wie folgt:
Jedes CR- oder LF-Zeichen sollte zur nächsten Zeile springen , AUSSER ...
... wenn auf eine CR unmittelbar LF ( \u000D\u000A) folgt, überspringen diese beiden zusammen nur eine Zeile.
String.Empty ist die einzige Eingabe, die keine Zeilen zurückgibt (jedes Zeichen enthält mindestens eine Zeile)
Die letzte Zeile muss zurückgegeben werden, auch wenn sie weder CR noch LF enthält.
Die vorstehende Regel beschreibt das Verhalten von StringReader.ReadLine und verwandten Funktionen. Die unten gezeigte Funktion führt zu identischen Ergebnissen. Es ist eine effiziente C # -Linienunterbrechungsfunktion, die diese Richtlinien pflichtbewusst umsetzt, um jede beliebige Sequenz oder Kombination von CR / LF korrekt zu handhaben. Die aufgezählten Zeilen enthalten keine CR / LF-Zeichen. Leere Zeilen bleiben erhalten und werden als zurückgegeben String.Empty.
/// <summary>/// Enumerates the text lines from the string./// ⁃ Mixed CR-LF scenarios are handled correctly/// ⁃ String.Empty is returned for each empty line/// ⁃ No returned string ever contains CR or LF/// </summary>publicstaticIEnumerable<String>Lines(thisString s){int j =0, c, i;char ch;if((c = s.Length)>0)do{for(i = j;(ch = s[j])!='\r'&& ch !='\n'&&++j < c;);yieldreturn s.Substring(i, j - i);}while(++j < c &&(ch !='\r'|| s[j]!='\n'||++j < c));}
Hinweis: Wenn Ihnen der Aufwand beim Erstellen einer StringReaderInstanz bei jedem Aufruf nichts ausmacht , können Sie stattdessen den folgenden C # 7- Code verwenden. Wie bereits erwähnt, ist das obige Beispiel zwar etwas effizienter, beide Funktionen führen jedoch zu genau denselben Ergebnissen.
publicstaticIEnumerable<String>Lines(thisString s){
using (var tr =newStringReader(s))while(tr.ReadLine()isString L)yieldreturn L;}
Antworten:
Wenn es hässlich aussieht, entfernen Sie einfach den unnötigen
ToCharArray
Anruf.Wenn Sie entweder
\n
oder teilen möchten\r
, haben Sie zwei Möglichkeiten:Verwenden Sie ein Array-Literal. Dadurch erhalten Sie jedoch leere Zeilen für Zeilenenden im Windows-Stil
\r\n
:Verwenden Sie einen regulären Ausdruck, wie von Bart angegeben:
Wenn Sie leere Zeilen beibehalten möchten, warum weisen Sie C # ausdrücklich an, sie wegzuwerfen? (
StringSplitOptions
Parameter) -StringSplitOptions.None
stattdessen verwenden.quelle
Environment.NewLine
ist es für mich ein No-Go. Tatsächlich bevorzuge ich von allen möglichen Lösungen die mit regulären Ausdrücken, da nur diese alle Quellplattformen korrekt handhabt.StringSplitOptions.RemoveEmptyEntries
.quelle
string.Split
oderRegex.Split
)?Update: Hier finden Sie eine alternative / asynchrone Lösung.
Dies funktioniert hervorragend und ist schneller als Regex:
Es ist wichtig,
"\r\n"
zuerst im Array zu haben, damit es als ein Zeilenumbruch genommen wird. Das Obige ergibt die gleichen Ergebnisse wie jede dieser Regex-Lösungen:Nur dass Regex ungefähr zehnmal langsamer ist. Hier ist mein Test:
Ausgabe:
00: 00: 03.8527616
00: 00: 31.8017726
00: 00: 32.5557128
und hier ist die Erweiterungsmethode:
Verwendung:
quelle
[\r\n]{1,2}
\n\r
oder\n\n
als einzelner Zeilenumbruch, was nicht korrekt ist.Hello\n\nworld\n\n
ein Edge Case? Es ist eindeutig eine Zeile mit Text, gefolgt von einer leeren Zeile, gefolgt von einer weiteren Zeile mit Text, gefolgt von einer leeren Zeile.Sie könnten Regex.Split verwenden:
Bearbeiten: hinzugefügt
|\r
, um (ältere) Mac-Leitungsabschlüsse zu berücksichtigen.quelle
\r
als Zeilenende verwendet werden.Wenn Sie leere Zeilen behalten möchten, entfernen Sie einfach die StringSplitOptions.
quelle
Ich hatte diese andere Antwort, aber diese, basierend auf Jacks Antwort ,
ist deutlich schneller und wirdmöglicherweise bevorzugt, da sie asynchron arbeitet, obwohl sie etwas langsamer ist.Verwendung:
Prüfung:
Ausgabe:
00: 00: 03.9603894
00: 00: 00.0029996
00: 00: 04.8221971
quelle
quelle
Leicht verdreht, aber ein Iteratorblock dafür:
Sie können dann anrufen:
quelle
quelle
Es ist schwierig, gemischte Zeilenenden richtig zu handhaben . Wie wir wissen, können die Leitungsabschluss Zeichen "Line Feed" (ASCII 10,
\n
,\x0A
,\u000A
), "Carriage Return" (ASCII 13\r
,\x0D
,\u000D
) oder eine Kombination von ihnen. Zurück zu DOS verwendet Windows die zweistellige Sequenz CR-LF\u000D\u000A
, daher sollte diese Kombination nur eine einzige Zeile ausgeben. Unix verwendet ein einzelnes\u000A
und sehr alte Macs verwenden ein einzelnes\u000D
Zeichen. Die Standardmethode zum Behandeln beliebiger Mischungen dieser Zeichen in einer einzelnen Textdatei lautet wie folgt:\u000D\u000A
) folgt, überspringen diese beiden zusammen nur eine Zeile.String.Empty
ist die einzige Eingabe, die keine Zeilen zurückgibt (jedes Zeichen enthält mindestens eine Zeile)Die vorstehende Regel beschreibt das Verhalten von StringReader.ReadLine und verwandten Funktionen. Die unten gezeigte Funktion führt zu identischen Ergebnissen. Es ist eine effiziente C # -Linienunterbrechungsfunktion, die diese Richtlinien pflichtbewusst umsetzt, um jede beliebige Sequenz oder Kombination von CR / LF korrekt zu handhaben. Die aufgezählten Zeilen enthalten keine CR / LF-Zeichen. Leere Zeilen bleiben erhalten und werden als zurückgegeben
String.Empty
.Hinweis: Wenn Ihnen der Aufwand beim Erstellen einer
StringReader
Instanz bei jedem Aufruf nichts ausmacht , können Sie stattdessen den folgenden C # 7- Code verwenden. Wie bereits erwähnt, ist das obige Beispiel zwar etwas effizienter, beide Funktionen führen jedoch zu genau denselben Ergebnissen.quelle