2012-10-30 36 views
10

Tôi có một mảng char rất lớn mà tôi cần phải chuyển đổi thành chuỗi để sử dụng Regex trên đó.
Nhưng nó quá lớn đến nỗi tôi nhận được OutOfMemoryException khi tôi chuyển cho nhà xây dựng chuỗi.Làm thế nào để tạo một chuỗi từ mảng char mà không cần sao chép nó?

Tôi biết chuỗi đó là bất biến và do đó nó không nên có thể chỉ định bộ sưu tập nhân vật cơ bản của nó nhưng tôi cần một cách để sử dụng biểu thức thông thường trên mà không cần sao chép toàn bộ điều.

Làm cách nào để nhận được mảng đó?

  • Tôi lấy từ tệp bằng cách sử dụng StreamReader. Tôi biết vị trí bắt đầu và độ dài của nội dung cần đọc, các phương pháp ReadReadBlock cần tôi cung cấp bộ đệm char[].

Vì vậy, đây là những điều tôi muốn biết:

  • Có cách nào để xác định thu underlaying một chuỗi? (Liệu nó thậm chí giữ các ký tự của nó trong một mảng?)
  • ... hoặc sử dụng Regex trực tiếp trên một mảng char?
  • ... hoặc nhận trực tiếp một phần của tệp dưới dạng chuỗi?
+2

Regex là gì? Nếu nó đủ đơn giản, bạn có thể thay thế nó bằng mã đi vào 'char []'. –

+0

Làm thế nào lớn là 'char []'? –

+0

@Matt: Thật không may là tôi không thể. Đó là một trình phân tích cú pháp khá dài và phức tạp. –

Trả lời

1

Tôi nghĩ rằng đặt cược tốt nhất của bạn là đọc nhiều chuỗi char [] thành các chuỗi riêng lẻ chồng chéo với một thứ nguyên nhất định. Bằng cách này, bạn sẽ có thể thực hiện Regex của bạn trên các khối riêng lẻ, và sự chồng chéo sẽ cung cấp cho bạn khả năng để đảm bảo rằng một "break" trong các khối không phá vỡ các mẫu tìm kiếm. Trong một psuedo mã cách:

int chunkSize = 100000; 
int overLap = 2000; 

for(int i = 0; i < myCharArray.length; i += chunkSize - overlap) 
{ 
    // Grab your array chunk into a partial string 
    // By having your iteration slightly smaller than 
    // your chunk size you guarantee not to miss any 
    // character groupings. You just need to make sure 
    // your overlap is sufficient to cover the expression 
    string chunk = new String(myCharArray.Skip(i).Take(chunkSize).ToArray()); 
    // run your regex 
} 
+1

Nhận xét: Không có lý do gì để sử dụng các phương thức LINQ ' Bỏ qua 'và' Take'. Có [một quá tải của các nhà xây dựng chuỗi] (http://msdn.microsoft.com/en-us/library/ms131424.aspx) để làm công cụ như thế này. Ngoài ra, phương thức Linq 'ToArray()' sẽ sao chép dữ liệu thêm một lần nữa. –

+0

+1. Đọc với các khối chồng lên nhau dường như là cách tiếp cận hợp lý để phù hợp với regex không xác định trong C#. Bình luận về bình luận: Tôi nghĩ rằng nó là ok để sử dụng Skip/Take trong mẫu vì nó cho thấy ý định tốt, và nó rõ ràng điều sai trái để làm như vậy không thể được sử dụng trực tiếp như sao chép-dán. –

+0

@ JeppeStigNielsen: Nó chỉ có nghĩa là psuedo-code và thay vì tìm kiếm phương pháp tốt nhất C# tôi đã đi với một cái gì đó tôi gõ thường xuyên mà có quan điểm của tôi trên. Nếu ai đó thực hiện đoạn mã trên, tôi sẽ đặt câu hỏi về sự tỉnh táo của họ. –

-1

Nếu bạn đang sử dụng .NET 4.0 hoặc cao hơn, những gì bạn nên sử dụng là một MemoryMappedFile. Lớp này được thiết kế độc quyền để bạn có thể thao tác các tệp rất lớn. Từ các tài liệu MSDN:

Một tập tin bộ nhớ ánh xạ bản đồ nội dung của một tập tin để địa chỉ logic không gian của một ứng dụng. Các tệp ánh xạ bộ nhớ cho phép các lập trình viên làm việc với các tệp cực lớn vì bộ nhớ có thể được quản lý đồng thời và cho phép truy cập ngẫu nhiên vào một tệp mà không cần tìm kiếm. Các tệp ánh xạ bộ nhớ cũng có thể được chia sẻ trên nhiều quy trình .

Khi bạn đã nhận được tệp ánh xạ bộ nhớ, hãy kiểm tra this Stack Overflow answer về cách áp dụng RegEx cho tệp ánh xạ bộ nhớ.

Hy vọng điều này sẽ hữu ích!

+0

-1. Không chắc chắn lý do tại sao sử dụng MemoryMappedFile sẽ tốt hơn StreamReader (một trong những sẽ phải đối phó với mã hóa bằng tay) ... cũng không rõ ràng nơi để có được phù hợp C# thực hiện cho mã Java để chạy Regex trên mảng byte. –

+0

@AlexeiLevenkov - MemoryMappedFile tốt hơn StreamReader vì StreamReader đọc toàn bộ tệp vào bộ nhớ. MemoryMappedFile phân vùng tệp thành cửa sổ hoặc chế độ xem cho phép bạn hoạt động trên một vùng cụ thể của tệp. MemoryMappedFile chỉ đọc trong số lượng byte mà bạn cần, chứ không phải là toàn bộ điều. – Icemanind

+4

@icemanind: Sai. StreamReader không đọc toàn bộ tệp vào bộ nhớ. – SLaks

1

Một tùy chọn khá xấu xí là sử dụng thư viện RegEx không được quản lý (như thư viện biểu thức chính quy POSIX) và mã không an toàn. Bạn có thể có được một con trỏ byte * vào mảng char và truyền nó trực tiếp đến thư viện không được quản lý, sau đó sắp xếp lại các phản hồi.

fixed (byte * pArray = largeCharArray) 
{ 
    // call unmanaged code with pArray 
} 
1

Nếu bạn có một nhân vật hoặc mẫu mà bạn có thể tìm kiếm được bảo đảm không có trong mô hình bạn đang cố gắng để tìm kiếm, bạn có thể quét các mảng cho nhân vật đó và tạo ra chuỗi nhỏ hơn để xử lý cá nhân . Quá trình sẽ giống như sau:

char token = '|'; 
int start = 0; 
int length = 0; 
for(int i = 0; i < charArray.Length; i++;) 
{ 
    if(charArray[i] == token) 
    { 
     string split = new string(charArray,start,length); 
     // check the string using the regex 

     // reset the length 
     length = 0; 
    } 
    else 
    { 
     length++; 
    } 
} 

Bằng cách đó bạn sao chép các phân đoạn nhỏ hơn của chuỗi sẽ được GC sau mỗi lần thử so với toàn bộ chuỗi.

Các vấn đề liên quan