Pregunta

Tal vez sea una pregunta básica, pero digamos que tengo una cadena de 2000 caracteres, necesito dividir esta cadena en un máximo de 512 caracteres cada una.

¿Hay una buena manera, como un bucle más o menos para hacer esto?

¿Fue útil?

Solución

Algo como esto:

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;
}

O simplemente para repetir:

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;
    }
}

Tenga en cuenta que esto se divide en fragmentos de unidades de código UTF-16, lo que no es lo mismo que dividir en fragmentos de puntos de código Unicode, que a su vez pueden no ser lo mismo que dividir en fragmentos de glifos.

Otros consejos

Aunque esta pregunta, mientras tanto, tiene una respuesta aceptada, aquí hay una versión corta con la ayuda de expresiones regulares. Es posible que a los puristas no les guste (comprensiblemente), pero cuando necesita una solución rápida y es hábil con las expresiones regulares, puede ser esta. El rendimiento es bastante bueno, sorprendentemente:

string [] split = Regex.Split(yourString, @"(?<=\G.{512})");

¿Qué hace? Mirada negativa hacia atrás y recordando la última posición con \G. También capturará el último bit, incluso si no es divisible por 512.

utilizando la implementación de Jon y la palabra clave rendimiento .

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));    
}

fuente: Dividir una cadena en trozos de cierto tamaño

Me atreveré a proporcionar una versión más LINQified de la solución de Jon, basada en el hecho de que el tipo string implementa 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;
}

La mayor parte de la respuesta puede tener el mismo defecto. Dado un texto vacío no darán nada. Nosotros (I) esperamos al menos recuperar esa cadena vacía (el mismo comportamiento que una división en un carácter que no está en la cadena, lo que devolverá un elemento: esa cadena dada)

por lo que deberíamos recorrer al menos una vez todo el tiempo (según el código de 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);
}

o usando un for ( Editado : después de jugar un poco más con esto, encontré una mejor manera de manejar el caso chunkSize mayor que el texto ):

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);
    }
}

Eso también podría usarse con el bucle do / while;)

Método de extensión genérico:

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 ();
  }
}

¿Algo así?

Calculate eachLength = StringLength / WantedCharLength
Then for (int i = 0; i < StringLength; i += eachLength)
SubString (i, eachLength);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top