質問

基本的な質問かもしれませんが、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>

を実装するという事実に基づいて、JonのソリューションのよりLINQifiedバージョンを提供することを敢えてします。
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);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top