Domanda

Forse una domanda di base ma diciamo che ho una stringa lunga 2000 caratteri, devo dividere questa stringa in blocchi di massimo 512 caratteri ciascuno.

C'è un modo carino, come un loop o giù di lì per farlo?

È stato utile?

Soluzione

Qualcosa del genere:

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 solo per scorrere:

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

Nota che questo si divide in blocchi di unità di codice UTF-16, che non è la stessa cosa della divisione in blocchi di punti di codice Unicode, che a loro volta potrebbero non essere la stessa divisione in blocchi di glifi.

Altri suggerimenti

Sebbene nel frattempo questa domanda abbia una risposta accettata, ecco una versione breve con l'aiuto di espressioni regolari. Ai puristi potrebbe non piacere (comprensibilmente) ma quando hai bisogno di una soluzione rapida e sei a tuo agio con le regex, può essere così. Le prestazioni sono piuttosto buone, sorprendentemente:

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

Cosa fa? Sguardo negativo all'indietro e ricordando l'ultima posizione con \G. Catturerà anche l'ultimo bit, anche se non è divisibile per 512.

utilizzando l'implementazione di Jon e la parola chiave rendimento .

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

fonte: Dividere una stringa in blocchi di una certa dimensione

Oserò fornire una versione LINQified della soluzione di Jon, in base al fatto che il 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 maggior parte della risposta potrebbe avere lo stesso difetto. Dato un testo vuoto non produrranno nulla. Ci aspettiamo (almeno) di recuperare quella stringa vuota (stesso comportamento di una divisione su un carattere non nella stringa, che restituirà un elemento: quella stringa data)

quindi dovremmo eseguire il loop almeno una volta tutte le volte (in base al codice di 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 per ( Modificato : dopo aver giocato un po 'di più con questo, ho trovato un modo migliore per gestire il caso chunkSize maggiore del testo ):

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

Che potrebbe anche essere usato con il ciclo do / while;)

Metodo di estensione generico:

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

Qualcosa del genere?

Calculate eachLength = StringLength / WantedCharLength
Then for (int i = 0; i < StringLength; i += eachLength)
SubString (i, eachLength);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top