Może podstawowe pytanie, ale powiedzmy, że mam ciąg znaków o długości 2000 znaków, muszę podzielić ten ciąg na maksymalnie 512 fragmentów znaków.Podziel ciąg w 512 kawałkach znaków
Czy jest jakiś fajny sposób, na przykład pętla?
Może podstawowe pytanie, ale powiedzmy, że mam ciąg znaków o długości 2000 znaków, muszę podzielić ten ciąg na maksymalnie 512 fragmentów znaków.Podziel ciąg w 512 kawałkach znaków
Czy jest jakiś fajny sposób, na przykład pętla?
coś takiego:
private IList<string> SplitIntoChunks(string text, int chunkSize)
{
List<string> chunks = new List<string>();
int offset = 0;
while (offset < text.Length)
{
int size = Math.Min(chunkSize, text.Length - offset);
chunks.Add(text.Substring(offset, size));
offset += size;
}
return chunks;
}
Albo po prostu iteracyjne nad:
private IEnumerable<string> SplitIntoChunks(string text, int chunkSize)
{
int offset = 0;
while (offset < text.Length)
{
int size = Math.Min(chunkSize, text.Length - offset);
yield return text.Substring(offset, size);
offset += size;
}
}
pamiętać, że ta dzieli się na kawałki UTF-16 jednostek kodu, który nie jest całkiem tak samo jak rozszczepienie w kawałki punktów kodu Unicode, które z kolei mogą nie być tym samym, co fragmenty glifów.
dammit Jon you pobili mnie do tego i użyłem twojej implementacji też ... –
Wiele się z tego nauczyłem. Zaakceptuj i daj +1. Bardzo dobrze! – janhartmann
Algorytm ten (i jego kompatybilność z Unicode) omówiono również w recenzji kodu: [Podziel ciąg na fragmenty o tej samej długości] (http://codereview.stackexchange.com/a/111925/13424). –
static IEnumerable<string> Split(string str, int chunkSize)
{
int len = str.Length;
return Enumerable.Range(0, len/chunkSize).Select(i => str.Substring(i * chunkSize, chunkSize));
}
+1 za kreatywność, -1 za wydajność i czytelność – Foxfire
Nie udało się dostarczyć ostatecznego fragmentu w tym przypadku. –
Coś takiego?
Calculate eachLength = StringLength/WantedCharLength
Then for (int i = 0; i < StringLength; i += eachLength)
SubString (i, eachLength);
Czy to C#? .... – Abel
będę śmiał zapewnić więcej LINQified wersję rozwiązania Jona, w oparciu o fakt, że typ string
realizuje IEnumerable<char>
:
private IList<string> SplitIntoChunks(string text, int chunkSize)
{
var chunks = new List<string>();
int offset = 0;
while(offset < text.Length) {
chunks.Add(new string(text.Skip(offset).Take(chunkSize).ToArray()));
offset += chunkSize;
}
return chunks;
}
Rozważyłem to - szczególnie, że MoreLINQ zapewnia ładną metodę podziału na tego typu rzeczy. Jednak efektywność tego byłaby absolutnie okropna :( –
Dobrze jest wiedzieć, że ponieważ używam LINQ do wszystkiego ... – Konamiman
btw String, nie ma metody rozszerzenia dla "Skip", co musiałbyś zrobić ToCharArray najpierw –
użyciu realizację Jona i plastyczności słowa kluczowego.
IEnumerable<string> Chunks(string text, int chunkSize)
{
for (int offset = 0; offset < text.Length; offset += chunkSize)
{
int size = Math.Min(chunkSize, text.Length - offset);
yield return text.Substring(offset, size);
}
}
Ciekawe użycie dla vs mój czas ... Jestem próbując zdecydować, który jest łatwiejszy do odczytania. Nie potrzebujesz przerwy na plonowanie na końcu, btw. –
Zrobiłem sobie prawo do naprawienia zbędnego limitu rentowności jako @Jon wspomniany –
dzięki, @LouisRhys :) –
Chociaż to pytanie ma na razie akceptowaną odpowiedź, oto krótka wersja z pomocą wyrażeń regularnych. Puryści mogą tego nie lubić (co zrozumiałe), ale kiedy potrzebujesz szybkiego rozwiązania i jesteś przydatny w przypadku wyrażeń regularnych, to może być to. Wydajność jest dość dobra, zaskakująco:
string [] split = Regex.Split(yourString, @"(?<=\G.{512})");
Co robi? Negatywne spojrzenie do tyłu i zapamiętanie ostatniej pozycji z \G
. Będzie także przechwytywał ostatni bit, nawet jeśli nie można go podzielić przez 512.
Przydatny do kontroli długich łańcuchów w okienku bezpośrednim. – Dialecticus
Dlaczego nie? Jest krótki, szybki i wyraźny (jeśli znasz regexes, osobiście musiałem go przeczytać i przetestować 3 razy). Dobra wersja! –
Większość odpowiedzi może mieć tę samą wadę. Biorąc pod uwagę pusty tekst, nic nie przyniosą. My (I) oczekujemy przynajmniej powrotu do tego pustego ciągu znaków (to samo zachowanie co split na znaku nie w ciągu znaków, który zwróci jeden element: ten podany ciąg)
, więc powinniśmy wykonać pętlę co najmniej raz czasy (na podstawie kodu Jona):
IEnumerable<string> SplitIntoChunks (string text, int chunkSize)
{
int offset = 0;
do
{
int size = Math.Min (chunkSize, text.Length - offset);
yield return text.Substring (offset, size);
offset += size;
} while (offset < text.Length);
}
lub za pomocą for (Edited: po bawiąc się trochę bardziej z tego, znalazłem lepszy sposób obsłużyć sprawę chunkSize większy niż tekst):
IEnumerable<string> SplitIntoChunks (string text, int chunkSize)
{
if (text.Length <= chunkSize)
yield return text;
else
{
var chunkCount = text.Length/chunkSize;
var remainingSize = text.Length % chunkSize;
for (var offset = 0; offset < chunkCount; ++offset)
yield return text.Substring (offset * chunkSize, chunkSize);
// yield remaining text if any
if (remainingSize != 0)
yield return text.Substring (chunkCount * chunkSize, remainingSize);
}
}
To może być również używany z do/while;)
Typowa metoda rozszerzenie:
using System;
using System.Collections.Generic;
using System.Linq;
public static class IEnumerableExtensions
{
public static IEnumerable<IEnumerable<T>> SplitToChunks<T> (this IEnumerable<T> coll, int chunkSize)
{
int skipCount = 0;
while (coll.Skip (skipCount).Take (chunkSize) is IEnumerable<T> part && part.Any())
{
skipCount += chunkSize;
yield return part;
}
}
}
class Program
{
static void Main (string[] args)
{
var col = Enumerable.Range(1,1<<10);
var chunks = col.SplitToChunks(8);
foreach (var c in chunks.Take (200))
{
Console.WriteLine (string.Join (" ", c.Select (n => n.ToString ("X4"))));
}
Console.WriteLine();
Console.WriteLine();
"Split this text into parts that are fifteen characters in length, surrounding each part with single quotes and output each into the console on seperate lines."
.SplitToChunks (15)
.Select(p => $"'{string.Concat(p)}'")
.ToList()
.ForEach (p => Console.WriteLine (p));
Console.ReadLine();
}
}
Czy na pewno chcesz char ** 512 ** kawałki? Ponieważ różni się od 512 ** bajtów **, co jest bardziej powszechnym ograniczeniem. –
@Henk: Z drugiej strony, dzielenie * tekstu * na porcje na podstawie * bajtów * byłoby dość dziwne - wyniki zależą od kodowania. –
Jon, tak, często występuje problem podczas ponownego składania tekstu. Ale niektóre kanały I/O działają w blokach 512-bajtowych. –