Supposons que j'avais une chaîne:
string str = "1111222233334444";
Comment puis-je diviser cette chaîne en morceaux d'une certaine taille?
par exemple, le diviser en tailles de 4 retournerait des chaînes:
"1111"
"2222"
"3333"
"4444"
Supposons que j'avais une chaîne:
string str = "1111222233334444";
Comment puis-je diviser cette chaîne en morceaux d'une certaine taille?
par exemple, le diviser en tailles de 4 retournerait des chaînes:
"1111"
"2222"
"3333"
"4444"
Réponses:
static IEnumerable<string> Split(string str, int chunkSize)
{
return Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize));
}
Veuillez noter qu'un code supplémentaire peut être requis pour gérer avec élégance les cas marginaux ( null
ou chaîne d'entrée vide chunkSize == 0
,, longueur de chaîne d'entrée non divisible par chunkSize
, etc.). La question d'origine ne spécifie aucune exigence pour ces cas marginaux et dans la vie réelle, les exigences peuvent varier et sont donc hors de portée de cette réponse.
(i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize
. Un problème supplémentaire est que cette fonction ne tient pas compte du fait que str est nul. Cela peut être corrigé en enveloppant toute la déclaration de retour dans une autre expression ternaire: (str != null) ? ... : Enumerable.Empty<String>();
.
str.Length / chunkSize
audouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
StringLength % 4 will always be 0
. Si ce Linq
n'est pas aussi facile à comprendre, il existe d'autres réponses qui utilisent des boucles et des rendements. Tout le monde est libre de choisir la solution qu'elle préfère. Vous pouvez poster votre code comme réponse et les gens voteront volontiers pour lui.
Dans une combinaison de colombe + réponses de Konstatin ...
static IEnumerable<string> WholeChunks(string str, int chunkSize) {
for (int i = 0; i < str.Length; i += chunkSize)
yield return str.Substring(i, chunkSize);
}
Cela fonctionnera pour toutes les chaînes qui peuvent être divisées en un nombre entier de morceaux et lèvera une exception dans le cas contraire.
Si vous souhaitez prendre en charge des chaînes de n'importe quelle longueur, vous pouvez utiliser le code suivant:
static IEnumerable<string> ChunksUpto(string str, int maxChunkSize) {
for (int i = 0; i < str.Length; i += maxChunkSize)
yield return str.Substring(i, Math.Min(maxChunkSize, str.Length-i));
}
Cependant, le PO a déclaré explicitement qu'il n'en avait pas besoin; c'est un peu plus long et plus difficile à lire, légèrement plus lent. Dans l'esprit de KISS et YAGNI, j'irais avec la première option: c'est probablement l'implémentation la plus efficace possible, et elle est très courte, lisible et, surtout, lève une exception pour les entrées non conformes.
Pourquoi pas des boucles? Voici quelque chose qui le ferait très bien:
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();
Je ne sais pas comment vous traiteriez le cas où la chaîne n'est pas un facteur de 4, mais ne dites pas que votre idée n'est pas possible, vous vous demandez simplement la motivation si une simple boucle for le fait très bien? Évidemment, ce qui précède pourrait être nettoyé et même mis en place comme méthode d'extension.
Ou comme mentionné dans les commentaires, vous savez que c'est / 4 alors
str = "1111222233334444";
for (int i = 0; i < stringLength; i += chunkSize)
{Console.WriteLine(str.Substring(i, chunkSize));}
int chunkSize = 4
de la boucle. Il ne sera modifié que lors de la dernière passe.
i += chunkSize
place.
str.Length
la boucle de la boucle et la placer dans une variable locale. L'optimiseur C # peut être en mesure d'inline la longueur du tableau, mais je pense que le code tel qu'il est écrit fera un appel de méthode sur chaque boucle, ce qui n'est pas efficace, car la taille de str
ne change jamais.
Utilisation d' expressions régulières et de Linq :
List<string> groups = (from Match m in Regex.Matches(str, @"\d{4}")
select m.Value).ToList();
Je trouve cela plus lisible, mais ce n'est qu'une opinion personnelle. Il peut également s'agir d'un aller simple:).
\d
classe de caractères par a .
et de spécifier RegexOptions.Singleline
.
Ceci est basé sur la solution @dove mais implémenté comme méthode d'extension.
Avantages:
Code
public static class EnumerableEx
{
public static IEnumerable<string> SplitBy(this string str, int chunkLength)
{
if (String.IsNullOrEmpty(str)) throw new ArgumentException();
if (chunkLength < 1) throw new ArgumentException();
for (int i = 0; i < str.Length; i += chunkLength)
{
if (chunkLength + i > str.Length)
chunkLength = str.Length - i;
yield return str.Substring(i, chunkLength);
}
}
}
Usage
var result = "bobjoecat".SplitBy(3); // bob, joe, cat
Tests unitaires supprimés par souci de concision (voir la révision précédente )
if (str.Length == 0) yield return String.Empty; else { for... }
IEnumerable
en tableau, surtout pas implicitement.
Chunkify
.. Ce n'est pas la mienne, je ne me souviens pas où j'ai vu ce nom, mais c'était très agréable pour moi
Comment est-ce pour un one-liner?
List<string> result = new List<string>(Regex.Split(target, @"(?<=\G.{4})", RegexOptions.Singleline));
Avec cette expression régulière, peu importe si le dernier morceau est inférieur à quatre caractères, car il ne regarde que les caractères derrière lui.
Je suis sûr que ce n'est pas la solution la plus efficace, mais je n'ai eu qu'à la lancer.
target.Lenght % ChunckSize == 0
cela renvoie une ligne vide supplémentaire, par exempleList<string> result = new List<string>(Regex.Split("fooo", @"(?<=\G.{4})", RegexOptions.Singleline));
Ce n'est pas joli et ce n'est pas rapide, mais ça marche, c'est une doublure et c'est LINQy:
List<string> a = text.Select((c, i) => new { Char = c, Index = i }).GroupBy(o => o.Index / 4).Select(g => new String(g.Select(o => o.Char).ToArray())).ToList();
ToCharArray
est inutile depuis l' string
est IEnumerable<char>
.
J'ai récemment dû écrire quelque chose qui accomplit cela au travail, alors j'ai pensé publier ma solution à ce problème. En prime, la fonctionnalité de cette solution fournit un moyen de diviser la chaîne dans la direction opposée et elle gère correctement les caractères unicode comme mentionné précédemment par Marvin Pinto ci-dessus. Voici donc:
using System;
using Extensions;
namespace TestCSharp
{
class Program
{
static void Main(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
{
public static class StringExtensions
{
/// <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>
public static string[] Split(this string s, int length)
{
System.Globalization.StringInfo str = new System.Globalization.StringInfo(s);
int lengthAbs = Math.Abs(length);
if (str == null || str.LengthInTextElements == 0 || lengthAbs == 0 || str.LengthInTextElements <= lengthAbs)
return new string[] { str.ToString() };
string[] array = new string[(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));
return array;
}
}
}
En outre, voici un lien d'image vers les résultats de l'exécution de ce code: http://i.imgur.com/16Iih.png
{str.ToString()}
à la fin de votre première déclaration IF. Êtes-vous sûr de ne pas vouloir dire str.String
? J'ai eu un problème avec le code ci-dessus, j'ai fait ce changement et tout a fonctionné.
Cela devrait être beaucoup plus rapide et plus efficace que l'utilisation de LINQ ou d'autres approches utilisées ici.
public static IEnumerable<string> Splice(this string s, int spliceLength)
{
if (s == null)
throw new ArgumentNullException("s");
if (spliceLength < 1)
throw new ArgumentOutOfRangeException("spliceLength");
if (s.Length == 0)
yield break;
var start = 0;
for (var end = spliceLength; end < s.Length; end += spliceLength)
{
yield return s.Substring(start, spliceLength);
start = end;
}
yield return s.Substring(start);
}
public static IEnumerable<IEnumerable<T>> SplitEvery<T>(this IEnumerable<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>>();
}
public static IEnumerable<T> Cons<T>(T x, IEnumerable<T> xs)
{
yield return x;
foreach (var xi in xs)
yield return xi;
}
Vous pouvez utiliser morelinq par Jon Skeet. Utilisez Batch comme:
string str = "1111222233334444";
int chunkSize = 4;
var chunks = str.Batch(chunkSize).Select(r => new String(r.ToArray()));
Cela renverra 4 morceaux pour la chaîne "1111222233334444"
. Si la longueur de la chaîne est inférieure ou égale à la taille du bloc Batch
, la chaîne sera renvoyée comme seul élément deIEnumerable<string>
Pour la sortie:
foreach (var chunk in chunks)
{
Console.WriteLine(chunk);
}
et cela donnera:
1111
2222
3333
4444
static IEnumerable<string> Split(string str, double chunkSize)
{
return Enumerable.Range(0, (int) Math.Ceiling(str.Length/chunkSize))
.Select(i => new string(str
.Skip(i * (int)chunkSize)
.Take((int)chunkSize)
.ToArray()));
}
et une autre approche:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var x = "Hello World";
foreach(var i in x.ChunkString(2)) Console.WriteLine(i);
}
}
public static class Ext{
public static IEnumerable<string> ChunkString(this string 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));
}
}
Six ans plus tard o_O
Juste parce que
public static IEnumerable<string> Split(this string str, int chunkSize, bool remainingInFront)
{
var count = (int) Math.Ceiling(str.Length/(double) chunkSize);
Func<int, int> start = index => remainingInFront ? str.Length - (count - index)*chunkSize : index*chunkSize;
Func<int, int> end = index => Math.Min(str.Length - Math.Max(start(index), 0), Math.Min(start(index) + chunkSize - Math.Max(start(index), 0), chunkSize));
return Enumerable.Range(0, count).Select(i => str.Substring(Math.Max(start(i), 0),end(i)));
}
ou
private static Func<bool, int, int, int, int, int> start = (remainingInFront, length, count, index, size) =>
remainingInFront ? length - (count - index) * size : index * size;
private static Func<bool, int, int, int, int, int, int> end = (remainingInFront, length, count, index, size, start) =>
Math.Min(length - Math.Max(start, 0), Math.Min(start + size - Math.Max(start, 0), size));
public static IEnumerable<string> Split(this string str, int chunkSize, bool remainingInFront)
{
var count = (int)Math.Ceiling(str.Length / (double)chunkSize);
return Enumerable.Range(0, count).Select(i => str.Substring(
Math.Max(start(remainingInFront, str.Length, count, i, chunkSize), 0),
end(remainingInFront, str.Length, count, i, chunkSize, start(remainingInFront, str.Length, count, i, chunkSize))
));
}
AFAIK tous les cas de bord sont traités.
Console.WriteLine(string.Join(" ", "abc".Split(2, false))); // ab c
Console.WriteLine(string.Join(" ", "abc".Split(2, true))); // a bc
Console.WriteLine(string.Join(" ", "a".Split(2, true))); // a
Console.WriteLine(string.Join(" ", "a".Split(2, false))); // a
static IEnumerable<string> Split(string str, int chunkSize)
{
IEnumerable<string> retVal = Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize))
if (str.Length % chunkSize > 0)
retVal = retVal.Append(str.Substring(str.Length / chunkSize * chunkSize, str.Length % chunkSize));
return retVal;
}
Il gère correctement la longueur de chaîne d'entrée non divisible par chunkSize.
Veuillez noter qu'un code supplémentaire peut être requis pour gérer correctement les cas marginaux (chaîne d'entrée nulle ou vide, chunkSize == 0).
Un conseil important si la chaîne qui est fragmentée doit prendre en charge tous les caractères Unicode.
Si la chaîne doit prendre en charge les caractères internationaux comme 𠀋
, divisez la chaîne à l'aide de la classe System.Globalization.StringInfo. À l'aide de StringInfo, vous pouvez fractionner la chaîne en fonction du nombre d'éléments de texte.
string internationalString = '𠀋';
La chaîne ci-dessus a une longueur de 2, car la String.Length
propriété renvoie le nombre d'objets Char dans cette instance, pas le nombre de caractères Unicode.
Meilleure réponse, la plus simple et la plus générique :).
string originalString = "1111222233334444";
List<string> test = new List<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))));
}
Substring
surcharge qui ne nécessite pas le paramètre de longueur originalString.Substring(i)
. Vous pouvez également utiliser >
au lieu de >=
dans votre chèque.
Personnellement je préfère ma solution :-)
Il gère:
Il est implémenté comme une méthode d'extension et calcule le nombre de morceaux à générer au préalable. Il vérifie le dernier morceau car dans le cas où la longueur du texte n'est pas un multiple, il doit être plus court. Propre, court, facile à comprendre ... et fonctionne!
public static string[] Split(this string value, int chunkSize)
{
if (string.IsNullOrEmpty(value)) throw new ArgumentException("The string cannot be null.");
if (chunkSize < 1) throw new ArgumentException("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 = new string[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;
}
List<string> SplitString(int chunk, string input)
{
List<string> list = new List<string>();
int cycles = input.Length / chunk;
if (input.Length % chunk != 0)
cycles++;
for (int i = 0; i < cycles; i++)
{
try
{
list.Add(input.Substring(i * chunk, chunk));
}
catch
{
list.Add(input.Substring(i * chunk));
}
}
return list;
}
Je pense que c'est une réponse simple:
public static IEnumerable<string> Split(this string str, int chunkSize)
{
if(string.IsNullOrEmpty(str) || chunkSize<1)
throw new ArgumentException("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)
yield return str.Substring(startIndex);
else
yield return str.Substring(startIndex, chunkSize);
}
}
Et cela couvre les cas marginaux.
Je sais que la question date de plusieurs années, mais voici une implémentation Rx. Il gère le length % chunkSize != 0
problème hors de la boîte:
public static IEnumerable<string> Chunkify(this string input, int size)
{
if(size < 1)
throw new ArgumentException("size must be greater than 0");
return input.ToCharArray()
.ToObservable()
.Buffer(size)
.Select(x => new string(x.ToArray()))
.ToEnumerable();
}
J'ai un peu développé la solution de João. Ce que j'ai fait différemment, c'est que dans ma méthode, vous pouvez réellement spécifier si vous voulez retourner le tableau avec les caractères restants ou si vous voulez les tronquer si les caractères de fin ne correspondent pas à la longueur de bloc requise, je pense que c'est assez flexible et le le code est assez simple:
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace SplitFunction
{
class Program
{
static void Main(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();
}
private static string[] 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 = (from Match m in Regex.Matches(text,pattern)select m.Value).ToArray();
return chunks;
}
}
}
public static List<string> SplitByMaxLength(this string str)
{
List<string> splitString = new List<string>();
for (int index = 0; index < str.Length; index += MaxLength)
{
splitString.Add(str.Substring(index, Math.Min(MaxLength, str.Length - index)));
}
return splitString;
}
Modifié légèrement pour renvoyer les pièces dont la taille n'est pas égale à chunkSize
public static IEnumerable<string> Split(this string str, int chunkSize)
{
var splits = new List<string>();
if (str.Length < chunkSize) { chunkSize = str.Length; }
splits.AddRange(Enumerable.Range(0, str.Length / chunkSize).Select(i => str.Substring(i * chunkSize, chunkSize)));
splits.Add(str.Length % chunkSize > 0 ? str.Substring((str.Length / chunkSize) * chunkSize, str.Length - ((str.Length / chunkSize) * chunkSize)) : string.Empty);
return (IEnumerable<string>)splits;
}
List
pour IEnumerable
; tout ce que cela fait est de cacher les fonctions spécifiques à la liste que vous voudrez peut-être utiliser. Il n'y a aucun inconvénient à simplement retourner le List
.
Je ne me souviens pas qui m'a donné ça, mais ça marche très bien. J'ai testé plusieurs façons de diviser les types énumérables en groupes. L'utilisation serait juste comme ça ...
List<string> Divided = Source3.Chunk(24).Select(Piece => string.Concat<char>(Piece)).ToList();
Le code d'extension ressemblerait à ceci ...
#region Chunk Logic
private class ChunkedEnumerable<T> : IEnumerable<T>
{
class ChildEnumerator : IEnumerator<T>
{
ChunkedEnumerable<T> parent;
int position;
bool done = false;
T current;
public ChildEnumerator(ChunkedEnumerable<T> parent)
{
this.parent = parent;
position = -1;
parent.wrapper.AddRef();
}
public T Current
{
get
{
if (position == -1 || done)
{
throw new InvalidOperationException();
}
return current;
}
}
public void Dispose()
{
if (!done)
{
done = true;
parent.wrapper.RemoveRef();
}
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
position++;
if (position + 1 > parent.chunkSize)
{
done = true;
}
if (!done)
{
done = !parent.wrapper.Get(position + parent.start, out current);
}
return !done;
}
public void Reset()
{
// per http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx
throw new NotSupportedException();
}
}
EnumeratorWrapper<T> wrapper;
int chunkSize;
int start;
public ChunkedEnumerable(EnumeratorWrapper<T> wrapper, int chunkSize, int start)
{
this.wrapper = wrapper;
this.chunkSize = chunkSize;
this.start = start;
}
public IEnumerator<T> GetEnumerator()
{
return new ChildEnumerator(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
private class EnumeratorWrapper<T>
{
public EnumeratorWrapper(IEnumerable<T> source)
{
SourceEumerable = source;
}
IEnumerable<T> SourceEumerable { get; set; }
Enumeration currentEnumeration;
class Enumeration
{
public IEnumerator<T> Source { get; set; }
public int Position { get; set; }
public bool AtEnd { get; set; }
}
public bool Get(int pos, out T item)
{
if (currentEnumeration != null && currentEnumeration.Position > pos)
{
currentEnumeration.Source.Dispose();
currentEnumeration = null;
}
if (currentEnumeration == null)
{
currentEnumeration = new Enumeration { Position = -1, Source = SourceEumerable.GetEnumerator(), AtEnd = false };
}
item = default(T);
if (currentEnumeration.AtEnd)
{
return false;
}
while (currentEnumeration.Position < pos)
{
currentEnumeration.AtEnd = !currentEnumeration.Source.MoveNext();
currentEnumeration.Position++;
if (currentEnumeration.AtEnd)
{
return false;
}
}
item = currentEnumeration.Source.Current;
return true;
}
int refs = 0;
// needed for dispose semantics
public void AddRef()
{
refs++;
}
public void RemoveRef()
{
refs--;
if (refs == 0 && currentEnumeration != null)
{
var copy = currentEnumeration;
currentEnumeration = null;
copy.Source.Dispose();
}
}
}
/// <summary>Speed Checked. Works Great!</summary>
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
if (chunksize < 1) throw new InvalidOperationException();
var wrapper = new EnumeratorWrapper<T>(source);
int currentPos = 0;
T ignore;
try
{
wrapper.AddRef();
while (wrapper.Get(currentPos, out ignore))
{
yield return new ChunkedEnumerable<T>(wrapper, chunksize, currentPos);
currentPos += chunksize;
}
}
finally
{
wrapper.RemoveRef();
}
}
#endregion
class StringHelper
{
static void Main(string[] args)
{
string str = "Hi my name is vikas bansal and my email id is bansal.vks@gmail.com";
int offSet = 10;
List<string> chunks = chunkMyStr(str, offSet);
Console.Read();
}
static List<string> chunkMyStr(string str, int offSet)
{
List<string> resultChunks = new List<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;
}
}
i += offSet
dans votre for
expression.
Modifié (maintenant il accepte tout non nul string
et tout positif chunkSize
) la solution de Konstantin Spirin :
public static IEnumerable<String> Split(String value, int chunkSize) {
if (null == value)
throw new ArgumentNullException("value");
else if (chunkSize <= 0)
throw new ArgumentOutOfRangeException("chunkSize", "Chunk size should be positive");
return Enumerable
.Range(0, value.Length / chunkSize + ((value.Length % chunkSize) == 0 ? 0 : 1))
.Select(index => (index + 1) * chunkSize < value.Length
? value.Substring(index * chunkSize, chunkSize)
: value.Substring(index * chunkSize));
}
Tests:
String source = @"ABCDEF";
// "ABCD,EF"
String test1 = String.Join(",", Split(source, 4));
// "AB,CD,EF"
String test2 = String.Join(",", Split(source, 2));
// "ABCDEF"
String test3 = String.Join(",", Split(source, 123));
static List<string> GetChunks(string value, int chunkLength)
{
var res = new List<string>();
int count = (value.Length / chunkLength) + (value.Length % chunkLength > 0 ? 1 : 0);
Enumerable.Range(0, count).ToList().ForEach(f => res.Add(value.Skip(f * chunkLength).Take(chunkLength).Select(z => z.ToString()).Aggregate((a,b) => a+b)));
return res;
}
Basé sur d'autres réponses d'affiches, ainsi que quelques exemples d'utilisation:
public static string FormatSortCode(string sortCode)
{
return ChunkString(sortCode, 2, "-");
}
public static string FormatIBAN(string iban)
{
return ChunkString(iban, 4, " ");
}
private static string ChunkString(string str, int chunkSize, string separator)
{
var b = new StringBuilder();
var stringLength = str.Length;
for (var i = 0; i < stringLength; i += chunkSize)
{
if (i + chunkSize > stringLength) chunkSize = stringLength - i;
b.Append(str.Substring(i, chunkSize));
if (i+chunkSize != stringLength)
b.Append(separator);
}
return b.ToString();
}
Utilisation des extensions Buffer de la bibliothèque IX
static IEnumerable<string> Split( this string str, int chunkSize )
{
return str.Buffer(chunkSize).Select(l => String.Concat(l));
}