Załóżmy, że mam ciąg:
string str = "1111222233334444";
Jak mogę rozbić ten sznur na kawałki o pewnym rozmiarze?
np. podzielenie tego na rozmiary 4 zwróci ciągi znaków:
"1111"
"2222"
"3333"
"4444"
Załóżmy, że mam ciąg:
string str = "1111222233334444";
Jak mogę rozbić ten sznur na kawałki o pewnym rozmiarze?
np. podzielenie tego na rozmiary 4 zwróci ciągi znaków:
"1111"
"2222"
"3333"
"4444"
Odpowiedzi:
static IEnumerable<string> Split(string str, int chunkSize)
{
return Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize));
}
Należy pamiętać, że może być wymagany dodatkowy kod, aby z wdziękiem obsługiwać przypadki na krawędziach ( nulllub pusty ciąg chunkSize == 0wejściowy, długość ciągu wejściowego nie jest podzielna przez chunkSizeitp.). Pierwotne pytanie nie określa żadnych wymagań dla tych przypadków skrajnych, a w rzeczywistości wymagania mogą się różnić, więc nie wchodzą w zakres tej odpowiedzi.
(i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize. Dodatkowym problemem jest to, że ta funkcja nie bierze pod uwagę, że str ma wartość NULL. To może być ustalona przez owinięcie całej instrukcji return w innym potrójnego wyrażeniem: (str != null) ? ... : Enumerable.Empty<String>();.
str.Length / chunkSizedodouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
StringLength % 4 will always be 0. Jeśli Linqnie jest to tak łatwe do zrozumienia, istnieją inne odpowiedzi, które używają pętli i wydajności. Każdy może wybrać rozwiązanie, które najbardziej mu się podoba. Możesz opublikować swój kod jako odpowiedź, a ludzie chętnie będą na niego głosować.
W kombinacji odpowiedzi dove + Konstatin ...
static IEnumerable<string> WholeChunks(string str, int chunkSize) {
for (int i = 0; i < str.Length; i += chunkSize)
yield return str.Substring(i, chunkSize);
}
Będzie to działać dla wszystkich ciągów, które można podzielić na całą liczbę porcji, i w przeciwnym razie wygeneruje wyjątek.
Jeśli chcesz obsługiwać ciągi dowolnej długości, możesz użyć następującego kodu:
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));
}
Jednak PO wyraźnie stwierdził, że tego nie potrzebuje; jest nieco dłuższy i trudniejszy do odczytania, nieco wolniejszy. W duchu KISS i YAGNI wybrałbym pierwszą opcję: jest to prawdopodobnie najbardziej wydajna możliwa implementacja, jest bardzo krótka, czytelna i, co ważne, wprowadza wyjątek dla niezgodnych danych wejściowych.
Dlaczego nie pętle? Oto coś, co zrobiłoby to całkiem dobrze:
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();
Nie wiem, jak poradziłbyś sobie z przypadkiem, w którym struna nie jest równa 4, ale nie mówię, że twój pomysł nie jest możliwy, zastanawiasz się, dlaczego jest to uzasadnione, jeśli prosta pętla for robi to bardzo dobrze? Oczywiście powyższe można oczyścić, a nawet zastosować jako metodę rozszerzenia.
Lub, jak wspomniano w komentarzach, wiesz, że to / 4
str = "1111222233334444";
for (int i = 0; i < stringLength; i += chunkSize)
{Console.WriteLine(str.Substring(i, chunkSize));}
int chunkSize = 4poza pętlę. Zostanie zmodyfikowany tylko przy ostatnim przejściu.
i += chunkSizetego.
str.Lengthpętlę z pętli do zmiennej lokalnej. Optymalizator C # może być w stanie wstawić długość tablicy, ale myślę, że kod jak napisany wykona wywołanie metody w każdej pętli, co nie jest wydajne, ponieważ rozmiar strnigdy się nie zmienia.
Używanie wyrażeń regularnych i Linq :
List<string> groups = (from Match m in Regex.Matches(str, @"\d{4}")
select m.Value).ToList();
Uważam, że jest to bardziej czytelne, ale to tylko osobista opinia. Może to być również jedna linijka:).
\dklasę znaków na .i określić RegexOptions.Singleline.
Jest to oparte na rozwiązaniu @dove, ale zaimplementowane jako metoda rozszerzenia.
Korzyści:
Kod
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);
}
}
}
Stosowanie
var result = "bobjoecat".SplitBy(3); // bob, joe, cat
Testy jednostkowe zostały usunięte ze względu na zwięzłość (patrz poprzednia wersja )
if (str.Length == 0) yield return String.Empty; else { for... }
IEnumerablena tablicę, szczególnie niejawnie.
Chunkify. To nie moja, nie pamiętam, gdzie widziałem tę nazwę, ale było mi bardzo przyjemnie
Jak to w przypadku jednej linijki?
List<string> result = new List<string>(Regex.Split(target, @"(?<=\G.{4})", RegexOptions.Singleline));
Z tym wyrażeniem regularnym nie ma znaczenia, czy ostatni fragment ma mniej niż cztery znaki, ponieważ zawsze patrzy tylko na znaki za nim.
Jestem pewien, że nie jest to najskuteczniejsze rozwiązanie, ale musiałem to po prostu rzucić.
target.Lenght % ChunckSize == 0tego zwraca dodatkowy pusty wiersz np.List<string> result = new List<string>(Regex.Split("fooo", @"(?<=\G.{4})", RegexOptions.Singleline));
Nie jest ładny i nie jest szybki, ale działa, jest jednowarstwowy i jest 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();
ToCharArrayjest niepotrzebne, ponieważ stringjest IEnumerable<char>.
Niedawno musiałem napisać coś, co to osiąga w pracy, więc pomyślałem, że opublikuję moje rozwiązanie tego problemu. Jako dodatkowy bonus, funkcjonalność tego rozwiązania zapewnia sposób na podzielenie łańcucha w przeciwnym kierunku i poprawnie obsługuje znaki Unicode, jak wcześniej wspomniano powyżej Marvin Pinto. Oto on:
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;
}
}
}
Ponadto znajduje się link do obrazu z wynikami uruchomienia tego kodu: http://i.imgur.com/16Iih.png
{str.ToString()}na końcu pierwszego wyciągu IF. Jesteś pewien, że nie miałeś na myśli str.String? Miałem problem z powyższym kodem, wprowadziłem tę zmianę i wszystko działało.
Powinno to być znacznie szybsze i bardziej wydajne niż używanie LINQ lub innych stosowanych tutaj podejść.
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;
}
Możesz użyć morelinq Jona Skeeta. Użyj partii jak:
string str = "1111222233334444";
int chunkSize = 4;
var chunks = str.Batch(chunkSize).Select(r => new String(r.ToArray()));
Zwróci 4 porcje dla łańcucha "1111222233334444". Jeśli długość ciągu jest mniejsza lub równa rozmiarowi fragmentu Batch, zwróci ciąg jako jedyny elementIEnumerable<string>
Do wyjścia:
foreach (var chunk in chunks)
{
Console.WriteLine(chunk);
}
i da:
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()));
}
i inne podejście:
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));
}
}
Sześć lat później o_O
Właśnie dlatego
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)));
}
lub
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 obsługiwane są wszystkie skrzynki krawędziowe.
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;
}
Prawidłowo obsługuje długość ciągu wejściowego niepodzielnego przez chunkSize.
Należy pamiętać, że może być wymagany dodatkowy kod, aby z wdziękiem obsługiwać przypadki na krawędziach (zerowy lub pusty ciąg wejściowy, chunkSize == 0).
Ważna wskazówka, jeśli fragmentowany ciąg musi obsługiwać wszystkie znaki Unicode.
Jeśli ciąg ma obsługiwać znaki międzynarodowe, takie jak 𠀋, podziel go przy użyciu klasy System.Globalization.StringInfo. Za pomocą StringInfo możesz podzielić ciąg znaków na podstawie liczby elementów tekstowych.
string internationalString = '𠀋';
Powyższy ciąg ma długość 2, ponieważ String.Lengthwłaściwość zwraca w tym przypadku liczbę obiektów Char, a nie liczbę znaków Unicode.
Najlepsza, najprostsza i ogólna odpowiedź :).
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))));
}
Substringprzeciążenia, które nie wymaga parametru długości originalString.Substring(i). Możesz także użyć >zamiast >=czeku.
Osobiście wolę moje rozwiązanie :-)
Obsługuje:
Został zaimplementowany jako metoda rozszerzenia i wcześniej oblicza liczbę porcji, które zostaną wygenerowane. Sprawdza ostatnią porcję, ponieważ jeśli długość tekstu nie jest wielokrotnością, musi być krótsza. Czysty, krótki, łatwy do zrozumienia ... i działa!
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;
}
Myślę, że jest to prosta odpowiedź:
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);
}
}
I obejmuje skrzynki krawędziowe.
Wiem, że pytanie ma już lata, ale tutaj jest implementacja Rx. Rozwiązuje length % chunkSize != 0problem po wyjęciu z pudełka:
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();
}
Lekko rozbudowałem rozwiązanie João. To, co zrobiłem inaczej, jest w mojej metodzie, możesz właściwie określić, czy chcesz zwrócić tablicę z pozostałymi znakami, czy też chcesz je obciąć, jeśli znaki końcowe nie pasują do wymaganej długości fragmentu, myślę, że jest dość elastyczny, a kod jest dość prosty:
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;
}
Zmieniono nieznacznie, aby zwracać części, których rozmiar nie jest równy 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;
}
Listdo IEnumerable; wystarczy ukryć funkcje specyficzne dla listy, których możesz chcieć użyć. Nie ma żadnej wady po prostu zwrot List.
Nie pamiętam, kto mi to dał, ale działa świetnie. Szybko przetestowałem kilka sposobów na podzielenie typów policzalnych na grupy. Użycie byłoby po prostu takie ...
List<string> Divided = Source3.Chunk(24).Select(Piece => string.Concat<char>(Piece)).ToList();
Kod rozszerzenia wyglądałby tak ...
#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 += offSetna swoje forwyrażenie.
Zmodyfikowany (obecnie przyjmuje żadnej non NULL stringi dowolną dodatnią chunkSize) Konstantin Spirin „s rozwiązanie:
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));
}
Testy:
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;
}
W oparciu o odpowiedzi innych plakatów oraz kilka przykładów użycia:
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();
}
Korzystanie z rozszerzeń bufora z biblioteki IX
static IEnumerable<string> Split( this string str, int chunkSize )
{
return str.Buffer(chunkSize).Select(l => String.Concat(l));
}