Вопрос

Может быть, основной вопрос, но допустим, у меня есть строка длиной 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.

используя реализацию Джона и ключевое слово 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: Разделение строки на куски определенного размера

Я позволю себе предоставить более LINQified версию решения Джона, основанную на том факте, что тип 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;
}

У большинства ответов может быть тот же недостаток. При пустом тексте они ничего не дадут. Мы (I) ожидаем, что, по крайней мере, вернем эту пустую строку (такое же поведение, что и при разбиении на символ, не входящий в строку, который вернет один элемент: данную строку)

поэтому мы должны выполнить цикл хотя бы один раз (на основе кода Джона):

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 ( отредактировано : после того, как я немного поигрался с этим, я нашел лучший способ обработать случай chunkSize больше, чем текст ):

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