質問
基本的な質問かもしれませんが、2000文字の文字列があるとしましょう。この文字列をそれぞれ最大512文字のチャンクに分割する必要があります。
これを行うためのループなどの良い方法はありますか?
解決
次のようなもの:
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;
}
または単に繰り返す:
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;
}
}
これはUTF-16コード単位のチャンクに分割されますが、これはUnicodeコードポイントのチャンクに分割することとはまったく同じではなく、グリフのチャンクに分割することとは異なる場合があります。
他のヒント
この質問には受け入れられた答えがありますが、正規表現の助けを借りた短いバージョンがあります。純粋主義者はそれを好まないかもしれません(当然)が、迅速な解決策が必要で、正規表現が便利な場合は、そうすることができます。驚くべきことにパフォーマンスはかなり良いです:
string [] split = Regex.Split(yourString, @"(?<=\G.{512})");
それは何ですか?後ろ向きに負になり、\G
で最後の位置を記憶します。 512で割り切れない場合でも、最後のビットもキャッチします。
Jonの実装と yield キーワードを使用します。
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);
}
}
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));
}
source:文字列をチャンクに分割特定のサイズの
string
型が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;
}
ほとんどの答えには同じ欠陥があるかもしれません。 空のテキストを指定すると、何も生成されません。 私たちは、少なくとも空の文字列を返すことを期待しています(文字列にない文字の分割と同じ動作、1つのアイテムを返します:その文字列)
したがって、少なくとも1回はすべてループする必要があります(Jonのコードに基づく):
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);
}
またはfor( Edited :これを少しいじった後、 chunkSizeがtext より大きい場合)を処理するより良い方法を見つけました:
>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);
}
}
これはdo / whileループでも使用できます;)
汎用拡張メソッド:
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 ();
}
}
次のようなものですか?
Calculate eachLength = StringLength / WantedCharLength
Then for (int i = 0; i < StringLength; i += eachLength)
SubString (i, eachLength);