2009-10-27 26 views
10

Có thể là câu hỏi cơ bản nhưng hãy để chúng tôi nói rằng tôi có một chuỗi dài 2000 ký tự, tôi cần chia chuỗi này thành tối đa 512 khối ký tự mỗi khối.Tách chuỗi trong 512 khối chữ

Có cách nào hay, giống như vòng lặp để thực hiện việc này?

+0

Bạn có chắc chắn bạn cần 512 ** char ** khối? Bởi vì đó là khác nhau từ 512 ** byte ** mà là một ràng buộc phổ biến hơn. –

+1

@Henk: Mặt khác, việc tách * văn bản * thành các khối dựa trên * byte * sẽ khá kỳ lạ - kết quả sẽ phụ thuộc vào mã hóa. –

+0

Jon, vâng, một vấn đề thường gặp khi lắp ráp lại văn bản. Nhưng một số kênh I/O hoạt động trong khối 512 byte. –

Trả lời

20

Something như thế này:

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

Hoặc chỉ để lặp qua:

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

Lưu ý rằng đây chia thành nhiều phần của-16 UTF đơn vị mã, đó là không hoàn toàn giống như tách thành các khối mã Unicode, mà lần lượt có thể không giống như tách thành các khối glyph.

+0

dammit Jon you đánh bại tôi với nó, và tôi đã sử dụng quá trình thực hiện của bạn ... –

+0

Tôi đã học được rất nhiều từ bài này. Chấp nhận và +1. Rất đẹp! – janhartmann

+0

Thuật toán này (và _compatibility_ với Unicode) cũng đã được thảo luận trong Đánh giá mã: [Chia chuỗi thành các đoạn có cùng độ dài] (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));  
} 

nguồn: Splitting a string into chunks of a certain size

+0

+1 cho sự sáng tạo, -1 cho hiệu suất và khả năng đọc – Foxfire

+9

Không cung cấp đoạn cuối cùng trong trường hợp này. –

-1

Something như thế nào?

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

Đây có phải là C#? .... – Abel

1

tôi sẽ dám để cung cấp một nhiều phiên bản LINQified dung dịch của Jon, dựa trên thực tế là loại string thực hiện 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

Tôi đã xem xét điều đó - đặc biệt là MoreLINQ cung cấp một phương pháp phân vùng tốt đẹp cho loại điều này. Tuy nhiên, hiệu quả của điều này sẽ hoàn toàn khủng khiếp: ( –

+0

Thật tuyệt khi biết rằng, vì tôi có xu hướng sử dụng LINQ cho mọi thứ ... – Konamiman

+0

btw Chuỗi, không có phương pháp mở rộng cho "Bỏ qua" bạn sẽ phải làm –

3

sử dụng thực hiện của Jon và năng suất từ khóa.

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

Thú vị sử dụng cho vs trong khi của tôi ... Tôi cố gắng quyết định cái nào dễ đọc hơn. Bạn không cần ngắt năng suất ở cuối, btw. –

+0

Tôi lấy quyền tự do để khắc phục thời gian nghỉ ngơi dự phòng như @Jon đã đề cập –

+0

cảm ơn, @LouisRhys :) –

3

Mặc dù câu hỏi này trong khi đó có câu trả lời được chấp nhận, đây là phiên bản ngắn với sự trợ giúp của cụm từ thông dụng. Purists có thể không thích nó (dễ hiểu) nhưng khi bạn cần một giải pháp nhanh chóng và bạn đang thuận tiện với regexes, điều này có thể được nó. Hiệu suất khá tốt, đáng ngạc nhiên:

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

Nó có tác dụng gì? Phủ định ngược lại và nhớ vị trí cuối cùng với \G. Nó cũng sẽ bắt được bit cuối cùng, ngay cả khi nó không thể chia cho 512.

+0

Hữu ích để kiểm tra chuỗi dài trong Cửa sổ ngay lập tức. – Dialecticus

+1

Tại sao không? Đó là ngắn, đủ nhanh và rõ ràng (nếu bạn biết regexes, cá nhân tôi đã phải đọc nó và kiểm tra nó 3 lần). Phiên bản đẹp! –

1

Hầu hết câu trả lời có thể có cùng một lỗi. Với một văn bản trống, chúng sẽ không tạo ra gì cả. Chúng tôi (I) mong đợi ít nhất để lấy lại chuỗi rỗng đó (cùng một hành vi như một sự chia tách trên một char không có trong chuỗi, sẽ trả lại một mục: chuỗi đã cho)

vì vậy chúng ta nên lặp lại ít nhất một lần mọi thời điểm (dựa trên mã của 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); 
} 

hoặc sử dụng cho (Edited: sau khi đùa giỡn một chút hơn với điều này, tôi tìm thấy một cách tốt hơn để xử lý các trường hợp chunkSize lớn hơn văn bản):

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

Đó cũng có thể được sử dụng với việc phải làm/Vòng lặp while;)

0

phương pháp khuyến nông Generic:

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