Se parecer feio, basta remover a ToCharArraychamada desnecessária .
Se você deseja dividir por um \nou por \r, você tem duas opções:
Use uma matriz literal - mas isso fornecerá linhas vazias para finais de linha no estilo do Windows \r\n:
var result = text.Split(new[]{'\r','\n'});
Use uma expressão regular, conforme indicado por Bart:
var result =Regex.Split(text,"\r\n|\r|\n");
Se você deseja preservar linhas vazias, por que você diz explicitamente ao C # para jogá-las fora? ( StringSplitOptionsparâmetro) - use em seu StringSplitOptions.Nonelugar.
Removendo ToCharArray fará específico da plataforma de código (nova linha pode ser '\ n')
Konstantin Spirin
1
@ Will: com a chance de você estar se referindo a mim em vez de Konstantin: Eu acredito ( fortemente ) que o código de análise deve se esforçar para trabalhar em todas as plataformas (ou seja, também deve ler arquivos de texto que foram codificados em plataformas diferentes da plataforma de execução) ) Então, para analisar, Environment.NewLineé um não-ir para mim. De fato, de todas as soluções possíveis, eu prefiro a que usa expressões regulares, pois somente ela lida com todas as plataformas de origem corretamente.
precisa saber é o seguinte
2
@ Hamish Bem, basta olhar para a documentação do enum, ou olhar na pergunta original! É StringSplitOptions.RemoveEmptyEntries.
Konrad Rudolph
8
Que tal o texto que contém '\ r \ n \ r \ n'. string.Split retornará 4 linhas vazias; no entanto, com '\ r \ n', ele deve fornecer 2. Fica pior se '\ r \ n' e '\ r' forem misturados em um arquivo.
username
1
@SurikovPavel Use a expressão regular. Essa é definitivamente a variante preferida, pois funciona corretamente com qualquer combinação de terminações de linha.
Konrad Rudolph
134
using (StringReader sr =newStringReader(text)){string line;while((line = sr.ReadLine())!=null){// do something}}
É importante ter o "\r\n"primeiro na matriz para que seja considerado como uma quebra de linha. O acima fornece os mesmos resultados que qualquer uma dessas soluções Regex:
Adicione mais alguns detalhes para tornar sua resposta mais útil para os leitores.
Mohit Jain
Feito. Também foi adicionado um teste para comparar seu desempenho com a solução Regex.
orad 8/08/14
Um pouco mais rápido padrão devido à menor retrocesso com a mesma funcionalidade se uma utilidades[\r\n]{1,2}
ΩmegaMan
@ OmegaMan Isso tem um comportamento diferente. Ele corresponderá \n\rou \n\ncomo quebra de linha única, o que não está correto.
orad 27/02
3
@OmegaMan Como é Hello\n\nworld\n\num caso extremo? É claramente uma linha com texto, seguida por uma linha vazia, seguida por outra linha com texto, seguida por uma linha vazia.
Brandin
36
Você pode usar o Regex.Split:
string[] tokens =Regex.Split(input,@"\r?\n|\r");
Editar: adicionado |\rà conta de terminadores de linha Mac (mais antigos).
Porém, isso não funcionará em arquivos de texto no estilo OS X, pois eles são usados apenas \rcomo final de linha.
9289 Konrad Rudolph
2
@ Konrad Rudolph: AFAIK, '\ r' foi usado em sistemas MacOS muito antigos e quase nunca é mais encontrado. Mas se o OP precisar dar conta disso (ou se eu estiver enganado), a regex pode ser facilmente estendida para dar conta dela, é claro: \ r? \ N | \ r
Bart Kiers
@Bart: Eu não acho que você está enganado, mas eu tenho repetidamente encontrou todos os possíveis finais de linha na minha carreira como programador.
9289 Konrad Rudolph
@ Konrad, você provavelmente está certo. Melhor prevenir do que remediar, eu acho.
227 Bart Kiers
1
@ EgamegaMan: Isso perderá linhas vazias, por exemplo, \ n \ n.
Mike Rosoft 21/03/19
9
Se você deseja manter linhas vazias, remova as StringSplitOptions.
var result = input.Split(System.Environment.NewLine.ToCharArray());
A nova linha pode ser '\ n' e o texto de entrada pode conter "\ n \ r".
Konstantin Spirin
4
Eu tive essa outra resposta, mas essa, com base na resposta de Jack , é significativamente mais rápida, pode ser preferida, pois funciona de forma assíncrona, embora um pouco mais 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;}}}}
Eu me pergunto se isso é porque você não está realmente inspecionando os resultados do enumerador e, portanto, ele não está sendo executado. Infelizmente, estou com preguiça de verificar.
precisa
Sim, é mesmo !! Quando você adiciona .ToList () às duas chamadas, a solução StringReader é realmente mais lenta! Na minha máquina é 6.74s vs. 5.10s
JCH2k
Isso faz sentido. Eu ainda prefiro esse método porque ele permite obter linhas de forma assíncrona.
Orad 6/11
Talvez você deve remover o cabeçalho "melhor solução" em sua outra resposta e editar este ...
É complicado lidar adequadamente com terminações de linhas mistas . Como sabemos, os personagens linha de terminação pode ser "Line Feed" (ASCII 10, \n, \x0A, \u000A), "Return" (ASCII 13, \r, \x0D, \u000D), ou alguma combinação deles. Voltando ao DOS, o Windows usa a sequência de dois caracteres CR-LF \u000D\u000A, portanto, essa combinação deve emitir apenas uma única linha. O Unix usa um único \u000AMacs e muito antigos usam um único \u000Dcaractere. A maneira padrão de tratar misturas arbitrárias desses caracteres em um único arquivo de texto é a seguinte:
cada caractere CR ou LF deve pular para a próxima linha, EXCETO ...
... se um CR é imediatamente seguido por LF ( \u000D\u000A), esses dois juntos pulam apenas uma linha.
String.Empty é a única entrada que não retorna linhas (qualquer caractere implica pelo menos uma linha)
A última linha deve ser retornada, mesmo que não tenha CR nem LF.
A regra anterior descreve o comportamento de StringReader.ReadLine e funções relacionadas, e a função mostrada abaixo produz resultados idênticos. É uma função eficiente de quebra de linha de C # que implementa obedientemente essas diretrizes para manipular corretamente qualquer sequência ou combinação arbitrária de CR / LF. As linhas enumeradas não contêm caracteres CR / LF. Linhas vazias são preservadas e retornadas 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: Se você não se importa com a sobrecarga de criar uma StringReaderinstância em cada chamada, pode usar o seguinte código C # 7 . Como observado, embora o exemplo acima possa ser um pouco mais eficiente, ambas as funções produzem exatamente os mesmos resultados.
publicstaticIEnumerable<String>Lines(thisString s){
using (var tr =newStringReader(s))while(tr.ReadLine()isString L)yieldreturn L;}
Respostas:
Se parecer feio, basta remover a
ToCharArray
chamada desnecessária .Se você deseja dividir por um
\n
ou por\r
, você tem duas opções:Use uma matriz literal - mas isso fornecerá linhas vazias para finais de linha no estilo do Windows
\r\n
:Use uma expressão regular, conforme indicado por Bart:
Se você deseja preservar linhas vazias, por que você diz explicitamente ao C # para jogá-las fora? (
StringSplitOptions
parâmetro) - use em seuStringSplitOptions.None
lugar.fonte
Environment.NewLine
é um não-ir para mim. De fato, de todas as soluções possíveis, eu prefiro a que usa expressões regulares, pois somente ela lida com todas as plataformas de origem corretamente.StringSplitOptions.RemoveEmptyEntries
.fonte
string.Split
ouRegex.Split
)?Atualização: Veja aqui uma solução alternativa / assíncrona.
Isso funciona muito bem e é mais rápido que o Regex:
É importante ter o
"\r\n"
primeiro na matriz para que seja considerado como uma quebra de linha. O acima fornece os mesmos resultados que qualquer uma dessas soluções Regex:Só que o Regex é 10 vezes mais lento. Aqui está o meu teste:
Resultado:
00: 00: 03.8527616
00: 00: 31.8017726
00: 00: 32.5557128
e aqui está o método de extensão:
Uso:
fonte
[\r\n]{1,2}
\n\r
ou\n\n
como quebra de linha única, o que não está correto.Hello\n\nworld\n\n
um caso extremo? É claramente uma linha com texto, seguida por uma linha vazia, seguida por outra linha com texto, seguida por uma linha vazia.Você pode usar o Regex.Split:
Editar: adicionado
|\r
à conta de terminadores de linha Mac (mais antigos).fonte
\r
como final de linha.Se você deseja manter linhas vazias, remova as StringSplitOptions.
fonte
Eu tive essa outra resposta, mas essa, com base na resposta de Jack ,
é significativamente mais rápida,pode ser preferida, pois funciona de forma assíncrona, embora um pouco mais lenta.Uso:
Teste:
Resultado:
00: 00: 03.9603894
00: 00: 00.0029996
00: 00: 04.8221971
fonte
fonte
Ligeiramente torcido, mas um bloco iterador para fazer isso:
Você pode ligar para:
fonte
fonte
É complicado lidar adequadamente com terminações de linhas mistas . Como sabemos, os personagens linha de terminação pode ser "Line Feed" (ASCII 10,
\n
,\x0A
,\u000A
), "Return" (ASCII 13,\r
,\x0D
,\u000D
), ou alguma combinação deles. Voltando ao DOS, o Windows usa a sequência de dois caracteres CR-LF\u000D\u000A
, portanto, essa combinação deve emitir apenas uma única linha. O Unix usa um único\u000A
Macs e muito antigos usam um único\u000D
caractere. A maneira padrão de tratar misturas arbitrárias desses caracteres em um único arquivo de texto é a seguinte:\u000D\u000A
), esses dois juntos pulam apenas uma linha.String.Empty
é a única entrada que não retorna linhas (qualquer caractere implica pelo menos uma linha)A regra anterior descreve o comportamento de StringReader.ReadLine e funções relacionadas, e a função mostrada abaixo produz resultados idênticos. É uma função eficiente de quebra de linha de C # que implementa obedientemente essas diretrizes para manipular corretamente qualquer sequência ou combinação arbitrária de CR / LF. As linhas enumeradas não contêm caracteres CR / LF. Linhas vazias são preservadas e retornadas como
String.Empty
.Nota: Se você não se importa com a sobrecarga de criar uma
StringReader
instância em cada chamada, pode usar o seguinte código C # 7 . Como observado, embora o exemplo acima possa ser um pouco mais eficiente, ambas as funções produzem exatamente os mesmos resultados.fonte