2009-10-27 14 views
10

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

C'è un modo carino, come un ciclo o così per fare questo?

+0

Sei sicuro bisogno di 512 ** char ** pezzi? Perché è diverso da 512 ** byte **, che è un vincolo più comune. –

+1

@Henk: D'altra parte, suddividere * testo * in blocchi basati su * byte * sarebbe piuttosto strano - i risultati dipenderebbero dalla codifica. –

+0

Jon, sì, un problema comune durante il riassemblaggio del testo. Ma alcuni canali I/O funzionano in blocchi da 512 byte. –

risposta

20

Qualcosa di simile a questo:

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 semplicemente per iterare su:

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

Si noti che questa si divide in pezzi di UTF-16 unità di codice, che non è proprio la stessa divisione in blocchi di punti di codice Unicode, che a loro volta potrebbero non essere la stessa cosa della suddivisione in blocchi di glifi.

+0

dannazione Jon tu Mi ha battuto e ho usato anche la tua implementazione ... –

+0

Ho imparato molto da questo. Accetta e +1. Molto bella! – janhartmann

+0

Questo algoritmo (e la sua _compatibilità_ con Unicode) è stato discusso anche su Code Review: [Suddividere una stringa in blocchi della stessa lunghezza] (http://codereview.stackexchange.com/a/111925/13424). –

1
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: Splitting a string into chunks of a certain size

+0

+1 per creatività, -1 per prestazioni e leggibilità – Foxfire

+9

In questo caso non è possibile fornire il blocco finale. –

-1

Qualcosa di simile?

Calculate eachLength = StringLength/WantedCharLength 
Then for (int i = 0; i < StringLength; i += eachLength) 
SubString (i, eachLength); 
+2

È questo C#? .... – Abel

1

oserò fornire una versione più LINQified della soluzione di Jon, sulla base del 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; 
} 
+1

L'ho preso in considerazione, in particolare perché MoreLINQ fornisce un buon metodo Partition per questo genere di cose. Tuttavia, l'efficienza di questo sarebbe assolutamente orribile :( –

+0

È bene sapere che, poiché tendo ad usare LINQ per tutto ... – Konamiman

+0

btw String, non ha un metodo di estensione per "Skip" che dovresti fare ToCharArray primo. –

3

usando implementazione di Jon e la resa parola chiave.

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

Uso interessante di contro vs mio mentre ... Io sono cercando di decidere quale è più facile da leggere. Non hai bisogno della pausa di rendimento alla fine, btw. –

+0

Mi sono preso la libertà di fissare l'interruzione di rendimento ridondante come @Jon menzionato –

+0

grazie, @LouisRhys :) –

3

Anche se questa domanda nel frattempo ha una risposta accettata, ecco una versione breve con l'aiuto di espressioni regolari. I puristi potrebbero non piacergli (comprensibilmente) ma quando hai bisogno di una soluzione rapida e sei a portata di mano con le regex, questo può essere. Le prestazioni sono piuttosto buone, sorprendentemente:

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

Che cosa fa? Negativo look-backward e ricordando l'ultima posizione con \G. Otterrà anche l'ultimo bit, anche se non è divisibile per 512.

+0

Utile per l'ispezione di stringhe lunghe nella Finestra Immediata. – Dialecticus

+1

Perché no? È breve, abbastanza veloce e chiaro (se si conoscono le regex, personalmente ho dovuto leggerlo e testarlo 3 volte). Bella versione! –

1

La maggior parte della risposta potrebbe avere lo stesso difetto. Dato un testo vuoto non daranno nulla. Noi (I) aspettiamo almeno di recuperare quella stringa vuota (lo stesso comportamento di una divisione su un char non nella stringa, che restituirà un elemento: quella stringa)

quindi dovremmo fare un ciclo almeno una volta tutti i tempi (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 utilizzando un per (Edited: dopo aver giocato un po 'di più con questo, ho trovato un modo migliore per gestire il caso chunksize maggiore di 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 essere utilizzato anche con il fai/while;)

0

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