Por que usar LINQ ou regexes quando as funções de manipulação de seqüência de caracteres padrão do C # podem fazer isso com menos esforço e mais velocidade? Além disso, o que acontece se a sequência tiver um número ímpar de caracteres?
22615 Ian Kemp
7
"Eu gostaria de evitar loops" - por quê?
30610 Mitch Wheat
12
Usar um loop simples é definitivamente o que oferece o melhor desempenho.
Guffa 20/09/09
4
nichesoftware.co.nz/blog/200909/linq-vs-loop-performance é uma comparação muito boa entre linq e loop real sobre uma matriz. Duvido que você encontre o linq mais rápido que o código escrito manualmente, porque ele continua chamando delegados em tempo de execução que são difíceis de otimizar. Linq é mais divertido embora :)
Blindy
2
Esteja você usando LINQ ou expressões regulares, o loop ainda está lá.
Observe que pode ser necessário código adicional para lidar com casos de borda normalmente ( nullou sequência de entrada vazia chunkSize == 0, comprimento da sequência de entrada não divisível por chunkSizeetc.). A pergunta original não especifica nenhum requisito para esses casos extremos e, na vida real, os requisitos podem variar, ficando fora do escopo desta resposta.
@ Harry Boa captura! Isso pode ser remediado com uma expressão ternária drop-in no parâmetro count de substring. Algo como: (i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize. Um problema adicional é que essa função não considera str sendo nulo. Isso pode ser corrigido por envolvimento toda a instrução de retorno em outra expressão ternária: (str != null) ? ... : Enumerable.Empty<String>();.
Tirou Spickes
7
Isso estava próximo, mas, diferentemente dos 30 upvoters anteriores, tive que alterar o limite de contagem de loops de Range de str.Length / chunkSizeparadouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
gap
4
@KonstantinSpirin Concordo se o código funcionou. Ele lida apenas com o caso em que uma string é um múltiplo de chunkSize, o restante da string é perdido. Por favor, emendar. Lembre-se também de que o LINQ e sua mágica não são tão fáceis de entender para quem quer apenas encontrar uma solução para esse problema. Uma pessoa agora deve entender o que as funções Enumerable.Range () e .Select () fazem. Não vou argumentar que você deve entender isso para escrever código C # /. NET, pois essas funções estão na BCL há muitos anos.
CodeMonkeyKing
6
O autor do tópico disse nos comentários que StringLength % 4 will always be 0. Se Linqnão é tão fácil de entender, existem outras respostas que usam loops e rendimentos. Qualquer pessoa é livre para escolher a solução que mais gosta. Você pode postar seu código como resposta e as pessoas votarão com prazer.
Konstantin Spirin
3
Enumerable.Range (0, (str.Length + chunkSize - 1) / chunkSize). Selecione (i => str.Substring (i * chunkSize, Math.Min (str.Length - i * chunkSize, chunkSize)))
Sten Petrov
135
Em uma combinação de respostas de pomba + Konstatin ...
staticIEnumerable<string>WholeChunks(string str,int chunkSize){for(int i =0; i < str.Length; i += chunkSize)yieldreturn str.Substring(i, chunkSize);}
Isso funcionará para todas as seqüências de caracteres que podem ser divididas em um número inteiro de partes e gerará uma exceção caso contrário.
Se você deseja suportar seqüências de caracteres de qualquer tamanho, pode usar o seguinte código:
staticIEnumerable<string>ChunksUpto(string str,int maxChunkSize){for(int i =0; i < str.Length; i += maxChunkSize)yieldreturn str.Substring(i,Math.Min(maxChunkSize, str.Length-i));}
No entanto, o OP declarou explicitamente que não precisa disso; é um pouco mais longo e difícil de ler, um pouco mais lento. No espírito do KISS e YAGNI, eu usaria a primeira opção: provavelmente é a implementação mais eficiente possível, e é muito curta, legível e, o que é mais importante, lança uma exceção para informações não conformes.
+1 vale um aceno de cabeça. meio que bate na cabeça. ele está procurando uma sintaxe sucinta e você também está dando o (provavelmente) melhor desempenho.
pomba
7
E se você o tornar "estático ... Chunk (esta string str, int chunkSize) {", você ainda terá mais um "novo" recurso C # nele. Em seguida, você pode escrever "1111222233334444" .Chunk (4).
22420 MartinStettner
1
@ MartinStettner: Essa é certamente uma ideia decente se essa é uma operação comum.
Eamon Nerbonne
Você deve incluir apenas o último código. O primeiro exige que você entenda e teste se a sequência é um múltiplo do tamanho de um pedaço antes de usar, ou entenda que ela não retornará o restante da sequência.
precisa saber é o seguinte
A pergunta do OP não deixa claro se ele precisa dessa funcionalidade. A primeira solução é mais simples, mais rápida e confiável falha, com uma exceção se a sequência não puder ser dividida igualmente no tamanho do bloco especificado. Concordo que retornar resultados "errados" seria ruim, mas não é o que acontece - isso apenas gera uma exceção; portanto, eu ficaria bem em usá-lo se você puder viver com a limitação.
Eamon Nerbonne
56
Por que não loops? Aqui está algo que faria muito bem:
string str ="111122223333444455";int chunkSize =4;int stringLength = str.Length;for(int i =0; i < stringLength ; i += chunkSize){if(i + chunkSize > stringLength) chunkSize = stringLength - i;Console.WriteLine(str.Substring(i, chunkSize));}Console.ReadLine();
Eu não sei como você lida com o caso em que a string não é fator de 4, mas não está dizendo que sua ideia não é possível, apenas imaginando a motivação para isso, se um loop for simples for muito bem? Obviamente, o acima pode ser limpo e até colocado como um método de extensão.
Ou, como mencionado nos comentários, você sabe que é / 4
str ="1111222233334444";for(int i =0; i < stringLength; i += chunkSize){Console.WriteLine(str.Substring(i, chunkSize));}
Você pode puxar para int chunkSize = 4fora do loop. Só será modificado no passe final.
John Feminella
+1 para uma solução simples e eficaz - é assim que eu o faria, embora eu o tivesse usado i += chunkSize.
22610 Ian Kemp
Provavelmente, uma queixa menor, mas você provavelmente também deve extrair str.Lengtho loop e entrar em uma variável local. O otimizador de C # pode ser capaz de alinhar o comprimento da matriz, mas acho que o código escrito fará uma chamada de método em cada loop, o que não é eficiente, pois o tamanho de strnunca muda.
Daniel Pryden
@ Daniel, coloque sua idéia lá. embora eu não tenho certeza de que isso não seria calculado em tempo de execução, mas isso é outra questão;)
pomba
@ Daniel retornando a isso, tenho certeza de que essa otimização seria extraída pelo compilador.
pomba
41
Usando expressões regulares e Linq :
List<string> groups =(fromMatch m inRegex.Matches(str,@"\d{4}")select m.Value).ToList();
Acho que isso é mais legível, mas é apenas uma opinião pessoal. Também pode ser uma linha:).
Mude o padrão para @ "\ d {1,4}" e funciona para qualquer comprimento de string. :)
Guffa 20/09/09
3
+1 Embora seja mais lento que as outras soluções, é definitivamente muito legível. Não está claro para mim se o OP exige dígitos ou caracteres arbitrários; provavelmente seria sensato substituir a \dclasse de caracteres por ae .especificar RegexOptions.Singleline.
Eamon Nerbonne
2
ou apenas Regex.Matches (s, @ "\ d {1,4}"). Selecione (m => m.Value) .ToList (); Eu nunca entendi essa sintaxe alternativa que serve apenas para ofuscar que estamos usando métodos de extensão.
The Dag
38
Isso é baseado na solução @dove mas implementado como um método de extensão.
Benefícios:
Método de extensão
Capas de canto
Divide a string com qualquer caractere: números, letras, outros símbolos
Código
publicstaticclassEnumerableEx{publicstaticIEnumerable<string>SplitBy(thisstring str,int chunkLength){if(String.IsNullOrEmpty(str))thrownewArgumentException();if(chunkLength <1)thrownewArgumentException();for(int i =0; i < str.Length; i += chunkLength){if(chunkLength + i > str.Length)
chunkLength = str.Length- i;yieldreturn str.Substring(i, chunkLength);}}}
Uso
var result ="bobjoecat".SplitBy(3);// bob, joe, cat
Testes de unidade removidos por questões de brevidade (consulte a revisão anterior )
Solução interessante, mas, a fim de evitar verificações além de nulo na entrada, parece mais lógico permitir que uma string vazia retorne apenas uma única parte de string vazia:if (str.Length == 0) yield return String.Empty; else { for... }
Nyerguds
Quero dizer, é assim que o String.Split normal lida com cadeias vazias; retorna uma entrada de sequência vazia.
Nyerguds
Nota lateral: seu exemplo de uso está errado. Você não pode simplesmente transmitir IEnumerablepara a matriz, especialmente não implicitamente.
Nyerguds
Eu pessoalmente gosto de chamar esse método Chunkify.. Não é minha, eu não me lembro onde eu vi esse nome, mas era muito bom para mim
quetzalcoatl
20
Como é isso para uma fila?
List<string> result =newList<string>(Regex.Split(target,@"(?<=\G.{4})",RegexOptions.Singleline));
Com esse regex, não importa se o último pedaço tem menos de quatro caracteres, porque apenas olha para os caracteres por trás dele.
Tenho certeza de que essa não é a solução mais eficiente, mas eu apenas tive que jogá-la lá fora.
no caso de target.Lenght % ChunckSize == 0isso retornar uma linha vazia adicional, por exemplo,List<string> result = new List<string>(Regex.Split("fooo", @"(?<=\G.{4})", RegexOptions.Singleline));
fubo
9
Não é bonito e não é rápido, mas funciona, é uma linha e é LINQy:
List<string> a = text.Select((c, i)=>new{Char= c,Index= i }).GroupBy(o => o.Index/4).Select(g =>newString(g.Select(o => o.Char).ToArray())).ToList();
É garantido que o GroupBy preserve a ordem dos elementos?
Konstantin Spirin
ToCharArrayé desnecessário, pois stringé IEnumerable<char>.
21415 Juhrr
8
Recentemente, tive que escrever algo que realizasse isso no trabalho, então pensei em publicar minha solução para esse problema. Como um bônus adicional, a funcionalidade desta solução fornece uma maneira de dividir a string na direção oposta e lida corretamente com caracteres unicode, como mencionado anteriormente por Marvin Pinto acima. Então aqui está:
using System;
using Extensions;
namespace TestCSharp{classProgram{staticvoidMain(string[] args){string asciiStr ="This is a string.";string unicodeStr ="これは文字列です。";string[] array1 = asciiStr.Split(4);string[] array2 = asciiStr.Split(-4);string[] array3 = asciiStr.Split(7);string[] array4 = asciiStr.Split(-7);string[] array5 = unicodeStr.Split(5);string[] array6 = unicodeStr.Split(-5);}}}
namespace Extensions{publicstaticclassStringExtensions{/// <summary>Returns a string array that contains the substrings in this string that are seperated a given fixed length.</summary>/// <param name="s">This string object.</param>/// <param name="length">Size of each substring./// <para>CASE: length > 0 , RESULT: String is split from left to right.</para>/// <para>CASE: length == 0 , RESULT: String is returned as the only entry in the array.</para>/// <para>CASE: length < 0 , RESULT: String is split from right to left.</para>/// </param>/// <returns>String array that has been split into substrings of equal length.</returns>/// <example>/// <code>/// string s = "1234567890";/// string[] a = s.Split(4); // a == { "1234", "5678", "90" }/// </code>/// </example> publicstaticstring[]Split(thisstring s,int length){System.Globalization.StringInfo str =newSystem.Globalization.StringInfo(s);int lengthAbs =Math.Abs(length);if(str ==null|| str.LengthInTextElements==0|| lengthAbs ==0|| str.LengthInTextElements<= lengthAbs)returnnewstring[]{ str.ToString()};string[]array=newstring[(str.LengthInTextElements% lengthAbs ==0? str.LengthInTextElements/ lengthAbs:(str.LengthInTextElements/ lengthAbs)+1)];if(length >0)for(int iStr =0, iArray =0; iStr < str.LengthInTextElements&& iArray <array.Length; iStr += lengthAbs, iArray++)array[iArray]= str.SubstringByTextElements(iStr,(str.LengthInTextElements- iStr < lengthAbs ? str.LengthInTextElements- iStr : lengthAbs));else// if (length < 0)for(int iStr = str.LengthInTextElements-1, iArray =array.Length-1; iStr >=0&& iArray >=0; iStr -= lengthAbs, iArray--)array[iArray]= str.SubstringByTextElements((iStr - lengthAbs <0?0: iStr - lengthAbs +1),(iStr - lengthAbs <0? iStr +1: lengthAbs));returnarray;}}}
Além disso, aqui está um link de imagem para os resultados da execução deste código: http://i.imgur.com/16Iih.png
Percebi um problema com este código. Você tem {str.ToString()}no final de sua primeira declaração IF. Tem certeza de que não quis dizer isso str.String? Eu tive um problema com o código acima, fiz essa alteração e tudo funcionou.
gunr2171
@ gunr2171 Parece que se str == null, essa linha também fornecerá uma NullReferenceException.
John Zabroski
5
Isso deve ser muito mais rápido e eficiente do que usar o LINQ ou outras abordagens usadas aqui.
publicstaticIEnumerable<string>Splice(thisstring s,int spliceLength){if(s ==null)thrownewArgumentNullException("s");if(spliceLength <1)thrownewArgumentOutOfRangeException("spliceLength");if(s.Length==0)yieldbreak;var start =0;for(var end = spliceLength; end < s.Length; end += spliceLength){yieldreturn s.Substring(start, spliceLength);
start = end;}yieldreturn s.Substring(start);}
Este olhares como ele faz a verificação cedo, mas isso não acontece. Você não recebe um erro até começar a enumerar o enumerável. Você precisa dividir sua função em duas partes, onde a primeira parte faz a verificação do argumento e, em seguida, retorna os resultados da segunda parte privada que faz a enumeração.
ErikE
4
publicstaticIEnumerable<IEnumerable<T>>SplitEvery<T>(thisIEnumerable<T> values,int n){var ls = values.Take(n);var rs = values.Skip(n);return ls.Any()?Cons(ls,SplitEvery(rs, n)):Enumerable.Empty<IEnumerable<T>>();}publicstaticIEnumerable<T>Cons<T>(T x,IEnumerable<T> xs){yieldreturn x;foreach(var xi in xs)yieldreturn xi;}
Isso retornará 4 pedaços para a sequência "1111222233334444". Se o comprimento da string for menor ou igual ao tamanho do pedaçoBatch , retornará a string como o único elemento deIEnumerable<string>
Para saída:
foreach(var chunk in chunks){Console.WriteLine(chunk);}
using System;
using System.Collections.Generic;
using System.Linq;publicclassProgram{publicstaticvoidMain(){var x ="Hello World";foreach(var i in x.ChunkString(2))Console.WriteLine(i);}}publicstaticclassExt{publicstaticIEnumerable<string>ChunkString(thisstring val,int chunkSize){return val.Select((x,i)=>new{Index= i,Value= x}).GroupBy(x => x.Index/chunkSize, x => x.Value).Select(x =>string.Join("",x));}}
Console.WriteLine(string.Join(" ","abc".Split(2,false)));// ab cConsole.WriteLine(string.Join(" ","abc".Split(2,true)));// a bcConsole.WriteLine(string.Join(" ","a".Split(2,true)));// aConsole.WriteLine(string.Join(" ","a".Split(2,false)));// a
E o caso da borda "entrada é uma string vazia"? Eu esperaria que, assim como no Split, retornasse um IEnumerable com uma única string contendo a entrada.
Nyerguds
3
Simples e curto:
// this means match a space or not a space (anything) up to 4 charactersvar lines =Regex.Matches(str,@"[\s\S]{0,4}").Cast<Match>().Select(x => x.Value);
Uma dica importante se a sequência que está sendo dividida em partes precisa suportar todos os caracteres Unicode.
Se a string for compatível com caracteres internacionais como 𠀋, divida-a usando a classe System.Globalization.StringInfo. Usando StringInfo, você pode dividir a sequência com base no número de elementos de texto.
string internationalString ='𠀋';
A sequência acima tem um Comprimento 2, porque a String.Lengthpropriedade retorna o número de objetos Char nessa instância, não o número de caracteres Unicode.
string originalString ="1111222233334444";List<string> test =newList<string>();int chunkSize =4;// change 4 with the size of strings you want.for(int i =0; i < originalString.Length; i = i + chunkSize){if(originalString.Length- i >= chunkSize)
test.Add(originalString.Substring(i, chunkSize));else
test.Add(originalString.Substring(i,((originalString.Length- i))));}
O cálculo do comprimento na última linha é redundante, basta usar a Substringsobrecarga que não requer o parâmetro length originalString.Substring(i). Além disso, você pode usar em >vez de >=no seu cheque.
Racil Hilan
@RacilHilan Vou testar as alterações de código com sua sugestão e atualizar a resposta. Fico feliz que alguém com essa reputação tenha tido tempo para revisar meu código. :) Obrigado, Sandeep
Sandeep Kushwah
2
Pessoalmente, prefiro minha solução :-)
Ele lida com:
Comprimentos de cadeia que são múltiplos do tamanho da parte.
Comprimentos de string que NÃO são múltiplos do tamanho do pedaço.
Comprimentos de string menores que o tamanho do pedaço.
Cadeias nulas e vazias (lança uma exceção).
Tamanhos de pedaços menores que 1 (lança uma exceção).
Ele é implementado como um método de extensão e calcula o número de pedaços que serão gerados previamente. Ele verifica o último pedaço porque, caso o tamanho do texto não seja múltiplo, ele precisa ser menor. Limpo, curto, fácil de entender ... e funciona!
publicstaticstring[]Split(thisstringvalue,int chunkSize){if(string.IsNullOrEmpty(value))thrownewArgumentException("The string cannot be null.");if(chunkSize <1)thrownewArgumentException("The chunk size should be equal or greater than one.");int remainder;int divResult =Math.DivRem(value.Length, chunkSize,out remainder);int numberOfChunks = remainder >0? divResult +1: divResult;var result =newstring[numberOfChunks];int i =0;while(i < numberOfChunks -1){
result[i]=value.Substring(i * chunkSize, chunkSize);
i++;}int lastChunkSize = remainder >0? remainder : chunkSize;
result[i]=value.Substring(i * chunkSize, lastChunkSize);return result;}
Eu gosto muito dessa resposta, mas talvez você deva usar if ((i + 1) * chunk> = input.Length) em vez de try / catch, pois as exceções são para casos excepcionais.
Nelsontruran
2
Eu acho que esta é uma resposta direta:
publicstaticIEnumerable<string>Split(thisstring str,int chunkSize){if(string.IsNullOrEmpty(str)|| chunkSize<1)thrownewArgumentException("String can not be null or empty and chunk size should be greater than zero.");var chunkCount = str.Length/ chunkSize +(str.Length% chunkSize !=0?1:0);for(var i =0; i < chunkCount; i++){var startIndex = i * chunkSize;if(startIndex + chunkSize >= str.Length)yieldreturn str.Substring(startIndex);elseyieldreturn str.Substring(startIndex, chunkSize);}}
Eu sei que a pergunta tem anos, mas aqui está uma implementação do Rx. Ele lida com o length % chunkSize != 0problema imediatamente:
publicstaticIEnumerable<string>Chunkify(thisstring input,int size){if(size <1)thrownewArgumentException("size must be greater than 0");return input.ToCharArray().ToObservable().Buffer(size).Select(x =>newstring(x.ToArray())).ToEnumerable();}
Eu desenvolvi um pouco a solução do João. O que fiz de maneira diferente é que, no meu método, você pode especificar se deseja retornar a matriz com os caracteres restantes ou se deseja truncá-los se os caracteres finais não corresponderem ao tamanho do pedaço necessário, acho que é bastante flexível e o código é bastante direto:
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace SplitFunction{classProgram{staticvoidMain(string[] args){string text ="hello, how are you doing today?";string[] chunks =SplitIntoChunks(text,3,false);if(chunks !=null){
chunks.ToList().ForEach(e =>Console.WriteLine(e));}Console.ReadKey();}privatestaticstring[]SplitIntoChunks(string text,int chunkSize,bool truncateRemaining){string chunk = chunkSize.ToString();string pattern = truncateRemaining ?".{"+ chunk +"}":".{1,"+ chunk +"}";string[] chunks =null;if(chunkSize >0&&!String.IsNullOrEmpty(text))
chunks =(fromMatch m inRegex.Matches(text,pattern)select m.Value).ToArray();return chunks;}}}
publicstaticList<string>SplitByMaxLength(thisstring str){List<string> splitString =newList<string>();for(int index =0; index < str.Length; index +=MaxLength){
splitString.Add(str.Substring(index,Math.Min(MaxLength, str.Length- index)));}return splitString;}
Não tenho certeza se vejo o uso de back-casting Listpara isso IEnumerable; tudo o que faz é ocultar funções específicas da lista que você pode querer usar. Não há nenhuma desvantagem em apenas retornar o arquivo List.
Nyerguds
1
Não me lembro de quem me deu isso, mas funciona muito bem. Eu testei várias maneiras de dividir tipos numerosos em grupos. O uso seria assim ...
classStringHelper{staticvoidMain(string[] args){string str ="Hi my name is vikas bansal and my email id is [email protected]";int offSet =10;List<string> chunks = chunkMyStr(str, offSet);Console.Read();}staticList<string> chunkMyStr(string str,int offSet){List<string> resultChunks =newList<string>();for(int i =0; i < str.Length; i += offSet){string temp = str.Substring(i,(str.Length- i)> offSet ? offSet :(str.Length- i));Console.WriteLine(temp);
resultChunks.Add(temp);}return resultChunks;}}
Respostas:
Observe que pode ser necessário código adicional para lidar com casos de borda normalmente (
null
ou sequência de entrada vaziachunkSize == 0
, comprimento da sequência de entrada não divisível porchunkSize
etc.). A pergunta original não especifica nenhum requisito para esses casos extremos e, na vida real, os requisitos podem variar, ficando fora do escopo desta resposta.fonte
(i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize
. Um problema adicional é que essa função não considera str sendo nulo. Isso pode ser corrigido por envolvimento toda a instrução de retorno em outra expressão ternária:(str != null) ? ... : Enumerable.Empty<String>();
.str.Length / chunkSize
paradouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
StringLength % 4 will always be 0
. SeLinq
não é tão fácil de entender, existem outras respostas que usam loops e rendimentos. Qualquer pessoa é livre para escolher a solução que mais gosta. Você pode postar seu código como resposta e as pessoas votarão com prazer.Em uma combinação de respostas de pomba + Konstatin ...
Isso funcionará para todas as seqüências de caracteres que podem ser divididas em um número inteiro de partes e gerará uma exceção caso contrário.
Se você deseja suportar seqüências de caracteres de qualquer tamanho, pode usar o seguinte código:
No entanto, o OP declarou explicitamente que não precisa disso; é um pouco mais longo e difícil de ler, um pouco mais lento. No espírito do KISS e YAGNI, eu usaria a primeira opção: provavelmente é a implementação mais eficiente possível, e é muito curta, legível e, o que é mais importante, lança uma exceção para informações não conformes.
fonte
Por que não loops? Aqui está algo que faria muito bem:
Eu não sei como você lida com o caso em que a string não é fator de 4, mas não está dizendo que sua ideia não é possível, apenas imaginando a motivação para isso, se um loop for simples for muito bem? Obviamente, o acima pode ser limpo e até colocado como um método de extensão.
Ou, como mencionado nos comentários, você sabe que é / 4
fonte
int chunkSize = 4
fora do loop. Só será modificado no passe final.i += chunkSize
.str.Length
o loop e entrar em uma variável local. O otimizador de C # pode ser capaz de alinhar o comprimento da matriz, mas acho que o código escrito fará uma chamada de método em cada loop, o que não é eficiente, pois o tamanho destr
nunca muda.Usando expressões regulares e Linq :
Acho que isso é mais legível, mas é apenas uma opinião pessoal. Também pode ser uma linha:).
fonte
\d
classe de caracteres por ae.
especificarRegexOptions.Singleline
.Isso é baseado na solução @dove mas implementado como um método de extensão.
Benefícios:
Código
Uso
Testes de unidade removidos por questões de brevidade (consulte a revisão anterior )
fonte
if (str.Length == 0) yield return String.Empty; else { for... }
IEnumerable
para a matriz, especialmente não implicitamente.Chunkify
.. Não é minha, eu não me lembro onde eu vi esse nome, mas era muito bom para mimComo é isso para uma fila?
Com esse regex, não importa se o último pedaço tem menos de quatro caracteres, porque apenas olha para os caracteres por trás dele.
Tenho certeza de que essa não é a solução mais eficiente, mas eu apenas tive que jogá-la lá fora.
fonte
target.Lenght % ChunckSize == 0
isso retornar uma linha vazia adicional, por exemplo,List<string> result = new List<string>(Regex.Split("fooo", @"(?<=\G.{4})", RegexOptions.Singleline));
Não é bonito e não é rápido, mas funciona, é uma linha e é LINQy:
fonte
ToCharArray
é desnecessário, poisstring
éIEnumerable<char>
.Recentemente, tive que escrever algo que realizasse isso no trabalho, então pensei em publicar minha solução para esse problema. Como um bônus adicional, a funcionalidade desta solução fornece uma maneira de dividir a string na direção oposta e lida corretamente com caracteres unicode, como mencionado anteriormente por Marvin Pinto acima. Então aqui está:
Além disso, aqui está um link de imagem para os resultados da execução deste código: http://i.imgur.com/16Iih.png
fonte
{str.ToString()}
no final de sua primeira declaração IF. Tem certeza de que não quis dizer issostr.String
? Eu tive um problema com o código acima, fiz essa alteração e tudo funcionou.Isso deve ser muito mais rápido e eficiente do que usar o LINQ ou outras abordagens usadas aqui.
fonte
fonte
Você pode usar o morelinq de Jon Skeet. Use o lote como:
Isso retornará 4 pedaços para a sequência
"1111222233334444"
. Se o comprimento da string for menor ou igual ao tamanho do pedaçoBatch
, retornará a string como o único elemento deIEnumerable<string>
Para saída:
e vai dar:
fonte
e outra abordagem:
fonte
Seis anos depois o_O
Só porque
ou
AFAIK todos os casos extremos são tratados.
fonte
Simples e curto:
fonte
.
?Ele manipula corretamente o comprimento da string de entrada não divisível por chunkSize.
Observe que pode ser necessário código adicional para lidar com casos extremos (seqüência de entrada nula ou vazia, chunkSize == 0).
fonte
Uma dica importante se a sequência que está sendo dividida em partes precisa suportar todos os caracteres Unicode.
Se a string for compatível com caracteres internacionais como
𠀋
, divida-a usando a classe System.Globalization.StringInfo. Usando StringInfo, você pode dividir a sequência com base no número de elementos de texto.A sequência acima tem um Comprimento 2, porque a
String.Length
propriedade retorna o número de objetos Char nessa instância, não o número de caracteres Unicode.fonte
Resposta melhor, mais fácil e genérica :).
fonte
Substring
sobrecarga que não requer o parâmetro lengthoriginalString.Substring(i)
. Além disso, você pode usar em>
vez de>=
no seu cheque.Pessoalmente, prefiro minha solução :-)
Ele lida com:
Ele é implementado como um método de extensão e calcula o número de pedaços que serão gerados previamente. Ele verifica o último pedaço porque, caso o tamanho do texto não seja múltiplo, ele precisa ser menor. Limpo, curto, fácil de entender ... e funciona!
fonte
fonte
Eu acho que esta é uma resposta direta:
E abrange casos extremos.
fonte
Eu sei que a pergunta tem anos, mas aqui está uma implementação do Rx. Ele lida com o
length % chunkSize != 0
problema imediatamente:fonte
Eu desenvolvi um pouco a solução do João. O que fiz de maneira diferente é que, no meu método, você pode especificar se deseja retornar a matriz com os caracteres restantes ou se deseja truncá-los se os caracteres finais não corresponderem ao tamanho do pedaço necessário, acho que é bastante flexível e o código é bastante direto:
fonte
fonte
Alterado ligeiramente para retornar peças cujo tamanho não seja igual a chunkSize
fonte
List
para issoIEnumerable
; tudo o que faz é ocultar funções específicas da lista que você pode querer usar. Não há nenhuma desvantagem em apenas retornar o arquivoList
.Não me lembro de quem me deu isso, mas funciona muito bem. Eu testei várias maneiras de dividir tipos numerosos em grupos. O uso seria assim ...
O código de extensão ficaria assim ...
fonte
fonte
i += offSet
para suafor
expressão.Modificado (agora aceita qualquer não nulo
string
e qualquer positivachunkSize
) Konstantin Spirin solução 's:Testes:
fonte
demonstração
fonte
Com base em outras respostas de pôsteres, além de algumas amostras de uso:
fonte
Usando as extensões de buffer da biblioteca IX
fonte