Si se ve feo, simplemente elimine la ToCharArrayllamada innecesaria .
Si desea dividir entre uno \nu otro \r, tiene dos opciones:
Use una matriz literal, 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 conservar las líneas vacías, ¿por qué le dice explícitamente a C # que las tire? ( StringSplitOptionsparámetro): use StringSplitOptions.Noneen su lugar.
La eliminación de ToCharArray hará que el código sea específico de la plataforma (NewLine puede ser '\ n')
Konstantin Spirin
1
@Will: en caso de que te refieras a mí en lugar de a Konstantin: creo ( firmemente ) que el código de análisis debería esforzarse por funcionar en todas las plataformas (es decir, también debería leer archivos de texto codificados en plataformas diferentes a la plataforma de ejecución ) Entonces, para analizar, Environment.NewLinees un no-go en lo que a mí respecta. De hecho, de todas las soluciones posibles, prefiero la que usa expresiones regulares, ya que solo eso maneja todas las plataformas de origen correctamente.
Konrad Rudolph
2
@Hamish Bueno, solo mira la documentación de la enumeración, ¡o mira la pregunta original! Es StringSplitOptions.RemoveEmptyEntries.
Konrad Rudolph
8
¿Qué tal el texto que contiene '\ r \ n \ r \ n'? string.Split devolverá 4 líneas vacías, sin embargo, con '\ r \ n' debería dar 2. Empeora si '\ r \ n' y '\ r' se mezclan en un archivo.
nombre de usuario
1
@SurikovPavel Use la expresión regular. Esa es definitivamente la variante preferida, ya que funciona correctamente con cualquier combinación de terminaciones de línea.
Konrad Rudolph el
134
using (StringReader sr =newStringReader(text)){string line;while((line = sr.ReadLine())!=null){// do something}}
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:
Agregue algunos detalles más para que su respuesta sea más útil para los lectores.
Mohit Jain
Hecho. También se agregó una prueba para comparar su rendimiento con la solución Regex.
Orad
Patrón algo más rápido debido a menos retroceso con la misma funcionalidad si se usa[\r\n]{1,2}
ΩmegaMan
@OmegaMan Eso tiene un comportamiento diferente. Coincidirá \n\ro \n\ncomo un salto de línea único que no es correcto.
orad
3
@OmegaMan ¿Cómo es Hello\n\nworld\n\nun caso extremo? Es claramente una línea con texto, seguida de una línea vacía, seguida de otra línea con texto, seguida de una línea vacía.
Brandin el
36
Puedes usar Regex.Split:
string[] tokens =Regex.Split(input,@"\r?\n|\r");
Editar: agregado |\ra la cuenta para terminadores de línea Mac (más antiguos).
Sin embargo, esto no funcionará en los archivos de texto de estilo OS X, ya que estos solo se usan \rcomo final de línea.
Konrad Rudolph el
2
@Konrad Rudolph: AFAIK, '\ r' se usó en sistemas MacOS muy antiguos y casi nunca se encuentra. Pero si el OP necesita tenerlo en cuenta (o si me equivoco), entonces la expresión regular puede extenderse fácilmente para tenerlo en cuenta, por supuesto: \ r? \ N | \ r
Bart Kiers
@Bart: Yo no creo que se equivoca, pero me he encontrado repetidamente todos los posibles finales de línea en mi carrera como programador.
Konrad Rudolph el
@ Konrad, probablemente tengas razón. Mejor prevenir que curar, supongo.
Bart Kiers el
1
@ ΩmegaMan: Eso perderá líneas vacías, por ejemplo, \ n \ n.
Mike Rosoft
9
Si desea mantener líneas vacías, simplemente elimine las StringSplitOptions.
var result = input.Split(System.Environment.NewLine.ToCharArray());
NewLine puede ser '\ n' y el texto de entrada puede contener "\ n \ r".
Konstantin Spirin
4
Tuve 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.
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;}}}}
Me pregunto si esto se debe a que en realidad no está inspeccionando los resultados del enumerador y, por lo tanto, no se está ejecutando. Lamentablemente, soy demasiado vago para comprobarlo.
James Holwell
Sí, en realidad lo es! Cuando agrega .ToList () a ambas llamadas, la solución StringReader es realmente más lenta. En mi máquina es 6.74s vs. 5.10s
JCH2k
Eso tiene sentido. Todavía prefiero este método porque me permite obtener líneas de forma asincrónica.
orad
Tal vez debería eliminar el encabezado de "mejor solución" en su otra respuesta y editar esta ...
Es complicado manejar correctamente las terminaciones de línea mixtas . Como sabemos, los caracteres de fin de línea pueden ser "salto de línea" (ASCII 10, \n, \x0A, \u000A), "retorno de carro" (ASCII 13, \r, \x0D, \u000D), o alguna combinación de ellos. Volviendo a DOS, Windows usa la secuencia de dos caracteres CR-LF \u000D\u000A, por lo que esta combinación solo debería emitir una sola línea. Unix usa un solo \u000A, y Macs muy antiguos usaban un solo \u000Dcarácter. La forma estándar de tratar mezclas arbitrarias de estos caracteres dentro de un solo archivo de texto es la siguiente:
todos y cada uno de los caracteres CR o LF deben pasar a la siguiente línea EXCEPTO ...
... si un CR es seguido inmediatamente por LF ( \u000D\u000A) entonces estos dos juntos saltan solo una línea.
String.Empty es la única entrada que no devuelve líneas (cualquier carácter implica al menos una línea)
La última línea debe devolverse incluso si no tiene CR ni LF.
La regla anterior describe el comportamiento de StringReader.ReadLine y funciones relacionadas, y la función que se muestra a continuación produce resultados idénticos. Es una función eficiente de salto de línea C # que implementa debidamente estas pautas para manejar correctamente cualquier secuencia arbitraria o combinación de CR / LF. Las líneas enumeradas no contienen ningún carácter CR / LF. Las líneas vacías se conservan y devuelven como 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));}
Nota: Si no le importa la sobrecarga de crear una StringReaderinstancia en cada llamada, puede usar el siguiente código C # 7 en su lugar. Como se señaló, aunque el ejemplo anterior puede ser un poco más eficiente, ambas funciones producen exactamente los mismos resultados.
publicstaticIEnumerable<String>Lines(thisString s){
using (var tr =newStringReader(s))while(tr.ReadLine()isString L)yieldreturn L;}
Respuestas:
Si se ve feo, simplemente elimine la
ToCharArray
llamada innecesaria .Si desea dividir entre uno
\n
u otro\r
, tiene dos opciones:Use una matriz literal, pero esto le dará líneas vacías para las terminaciones de línea estilo Windows
\r\n
:Use una expresión regular, como lo indica Bart:
Si desea conservar las líneas vacías, ¿por qué le dice explícitamente a C # que las tire? (
StringSplitOptions
parámetro): useStringSplitOptions.None
en su lugar.fuente
Environment.NewLine
es un no-go en lo que a mí respecta. De hecho, de todas las soluciones posibles, prefiero la que usa expresiones regulares, ya que solo eso maneja todas las plataformas de origen correctamente.StringSplitOptions.RemoveEmptyEntries
.fuente
string.Split
oRegex.Split
)?Actualización: Vea aquí para una solución alternativa / asíncrona.
Esto funciona muy bien y es más rápido que Regex:
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:Excepto que Regex resulta ser aproximadamente 10 veces más lento. Aquí está mi prueba:
Salida:
00: 00: 03.8527616
00: 00: 31.8017726
00: 00: 32.5557128
y aquí está el método de extensión:
Uso:
fuente
[\r\n]{1,2}
\n\r
o\n\n
como un salto de línea único que no es correcto.Hello\n\nworld\n\n
un caso extremo? Es claramente una línea con texto, seguida de una línea vacía, seguida de otra línea con texto, seguida de una línea vacía.Puedes usar Regex.Split:
Editar: agregado
|\r
a la cuenta para terminadores de línea Mac (más antiguos).fuente
\r
como final de línea.Si desea mantener líneas vacías, simplemente elimine las StringSplitOptions.
fuente
Tuve 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.Uso:
Prueba:
Salida:
00: 00: 03.9603894
00: 00: 00.0029996
00: 00: 04.8221971
fuente
fuente
Ligeramente torcido, pero un bloque iterador para hacerlo:
Entonces puede llamar:
fuente
fuente
Es complicado manejar correctamente las terminaciones de línea mixtas . Como sabemos, los caracteres de fin de línea pueden ser "salto de línea" (ASCII 10,
\n
,\x0A
,\u000A
), "retorno de carro" (ASCII 13,\r
,\x0D
,\u000D
), o alguna combinación de ellos. Volviendo a DOS, Windows usa la secuencia de dos caracteres CR-LF\u000D\u000A
, por lo que esta combinación solo debería emitir una sola línea. Unix usa un solo\u000A
, y Macs muy antiguos usaban un solo\u000D
carácter. La forma estándar de tratar mezclas arbitrarias de estos caracteres dentro de un solo archivo de texto es la siguiente:\u000D\u000A
) entonces estos dos juntos saltan solo una línea.String.Empty
es la única entrada que no devuelve líneas (cualquier carácter implica al menos una línea)La regla anterior describe el comportamiento de StringReader.ReadLine y funciones relacionadas, y la función que se muestra a continuación produce resultados idénticos. Es una función eficiente de salto de línea C # que implementa debidamente estas pautas para manejar correctamente cualquier secuencia arbitraria o combinación de CR / LF. Las líneas enumeradas no contienen ningún carácter CR / LF. Las líneas vacías se conservan y devuelven como
String.Empty
.Nota: Si no le importa la sobrecarga de crear una
StringReader
instancia en cada llamada, puede usar el siguiente código C # 7 en su lugar. Como se señaló, aunque el ejemplo anterior puede ser un poco más eficiente, ambas funciones producen exactamente los mismos resultados.fuente