La mejor manera de dividir la cadena en líneas

¿Cómo se divide el hilo de varias líneas en líneas?

Lo sé de esta manera

var result = input.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 

se ve un poco feo y pierde líneas vacías. ¿Hay una mejor solución?

  • Si parece feo, simplemente elimine la llamada ToCharArray innecesaria.

  • Si quieres dividir entre \n o \r , tienes dos opciones:

    • Utilice un literal de matriz, pero esto le dará líneas vacías para las terminaciones de línea estilo Windows \r\n :

       var result = text.Split(new [] { '\r', '\n' }); 
    • Use una expresión regular, como lo indica Bart:

       var result = Regex.Split(text, "\r\n|\r|\n"); 
  • Si desea preservar las líneas vacías, ¿por qué explícitamente le dice a C # que las deseche? (Parámetro StringSplitOptions ) – use StringSplitOptions.None en StringSplitOptions.None lugar.

 using (StringReader sr = new StringReader(text)) { string line; while ((line = sr.ReadLine()) != null) { // do something } } 

Podría usar Regex.Split:

 string[] tokens = Regex.Split(input, @"\r?\n|\r"); 

Editar: añadido |\r para dar cuenta de los terminadores de línea Mac (más antiguos).

Actualización: mira aquí para una solución alternativa / asíncrona.


Esto funciona muy bien y es más rápido que Regex:

 input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None) 

Es importante tener "\r\n" primero en la matriz para que se tome como un salto de línea. Lo anterior da los mismos resultados que cualquiera de estas soluciones Regex:

 Regex.Split(input, "\r\n|\r|\n") Regex.Split(input, "\r?\n|\r") 

Excepto que Regex resulta ser unas 10 veces más lento. Aquí está mi prueba:

 Action measure = (Action func) => { var start = DateTime.Now; for (int i = 0; i < 100000; i++) { func(); } var duration = DateTime.Now - start; Console.WriteLine(duration); }; var input = ""; for (int i = 0; i < 100; i++) { input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n"; } measure(() => input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None) ); measure(() => Regex.Split(input, "\r\n|\r|\n") ); measure(() => Regex.Split(input, "\r?\n|\r") ); 

Salida:

00: 00: 03.8527616

00: 00: 31.8017726

00: 00: 32.5557128

y aquí está el Método de Extensión:

 public static class StringExtensionMethods { public static IEnumerable GetLines(this string str, bool removeEmptyLines = false) { return str.Split(new[] { "\r\n", "\r", "\n" }, removeEmptyLines ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None); } } 

Uso:

 input.GetLines() // keeps empty lines input.GetLines(true) // removes empty lines 

Si desea mantener líneas vacías, simplemente elimine StringSplitOptions.

 var result = input.Split(System.Environment.NewLine.ToCharArray()); 

Tenía esta otra respuesta, pero esta, basada en la respuesta de Jack, es significativamente más rápida , ya que funciona de forma asíncrona, aunque un poco más lenta.

 public static class StringExtensionMethods { public static IEnumerable GetLines(this string str, bool removeEmptyLines = false) { using (var sr = new StringReader(str)) { string line; while ((line = sr.ReadLine()) != null) { if (removeEmptyLines && String.IsNullOrWhiteSpace(line)) { continue; } yield return line; } } } } 

Uso:

 input.GetLines() // keeps empty lines input.GetLines(true) // removes empty lines 

Prueba:

 Action measure = (Action func) => { var start = DateTime.Now; for (int i = 0; i < 100000; i++) { func(); } var duration = DateTime.Now - start; Console.WriteLine(duration); }; var input = ""; for (int i = 0; i < 100; i++) { input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n"; } measure(() => input.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None) ); measure(() => input.GetLines() ); measure(() => input.GetLines().ToList() ); 

Salida:

00: 00: 03.9603894

00: 00: 00.0029996

00: 00: 04.8221971

Ligeramente torcido, pero un bloque iterador para hacerlo:

 public static IEnumerable Lines(this string Text) { int cIndex = 0; int nIndex; while ((nIndex = Text.IndexOf(Environment.NewLine, cIndex + 1)) != -1) { int sIndex = (cIndex == 0 ? 0 : cIndex + 1); yield return Text.Substring(sIndex, nIndex - sIndex); cIndex = nIndex; } yield return Text.Substring(cIndex + 1); } 

A continuación, puede llamar:

 var result = input.Lines().ToArray(); 
  char[] archDelim = new char[] { '\r', '\n' }; words = asset.text.Split(archDelim, StringSplitOptions.RemoveEmptyEntries); 
  private string[] GetLines(string text) { List lines = new List(); using (MemoryStream ms = new MemoryStream()) { StreamWriter sw = new StreamWriter(ms); sw.Write(text); sw.Flush(); ms.Position = 0; string line; using (StreamReader sr = new StreamReader(ms)) { while ((line = sr.ReadLine()) != null) { lines.Add(line); } } sw.Close(); } return lines.ToArray(); }