2011-01-17 44 views
8

Có cách nào để đọc một tập tin văn bản trong D không?Đọc Tập tin Văn bản trong D

Yêu cầu là chức năng tự động phát hiện mã hóa và cung cấp cho tôi toàn bộ dữ liệu của tệp theo định dạng nhất quán, như string hoặc dstring. Nó sẽ tự động phát hiện các BOM và diễn giải chúng khi thích hợp.

Tôi đã thử std.file.readText() nhưng nó không xử lý các mã hóa khác nhau tốt.

(Tất nhiên, điều này sẽ có một tỷ lệ thất bại khác không, và đó là chấp nhận được cho các ứng dụng của tôi.)

Trả lời

8

Tôi tin rằng các tùy chọn thực tế duy nhất cho tập tin I/O trong Phobos vào thời điểm này (ngoài gọi các hàm C) là std.file.readTextstd.stdio.File. readText sẽ đọc trong một tệp dưới dạng một chuỗi ký tự, ký tự, hoặc dchars (mặc định là không thay đổi (char) [] - tức là chuỗi). Tôi tin rằng việc mã hóa phải là UTF-8, UTF-16 và UTF-32 cho các ký tự, ký tự, và dchars tương ứng, mặc dù tôi phải đi đào trong mã nguồn để chắc chắn. Bất kỳ mã hóa nào tương thích với các mã hóa đó (ví dụ: ASCII tương thích với UTF-8) sẽ hoạt động tốt.

Nếu bạn sử dụng File, khi đó bạn có một số tùy chọn cho các chức năng để đọc tệp - bao gồm readlnrawRead. Tuy nhiên, về cơ bản bạn đọc tệp bằng cách sử dụng mã hóa tương thích UTF-8, UTF-16 hoặc UTF-32 giống như với readText hoặc bạn đọc nó dưới dạng dữ liệu nhị phân và tự mình thao tác.

Vì, các loại ký tự trong D là char, wchar và dchar, là các đơn vị mã UTF-8, UTF-16 và UTF-32 tương ứng, trừ khi bạn muốn đọc dữ liệu ở định dạng nhị phân, tệp sẽ phải được mã hóa trong một mã hóa tương thích với một trong ba loại unicode đó. Với một chuỗi trong một mã hóa cụ thể, bạn có thể chuyển đổi nó thành mã hóa khác bằng cách sử dụng các hàm trong std.utf. Tuy nhiên, tôi không biết bất kỳ cách nào để truy vấn một tệp cho loại mã hóa của nó ngoài việc sử dụng readText để thử và đọc tệp trong một mã hóa đã cho và xem liệu nó có thành công hay không. Vì vậy, trừ khi bạn muốn tự mình xử lý và xác định xem mã hóa của nó là gì, đặt cược tốt nhất của bạn có thể chỉ sử dụng readText với từng loại chuỗi liên tiếp, sử dụng loại đầu tiên thành công. Tuy nhiên, vì các tệp văn bản thường là UTF-8 hoặc mã hóa tương thích UTF-8, tôi mong rằng readText được sử dụng với một chuỗi bình thường hầu như luôn hoạt động tốt.

+0

Hm ... bất kỳ ý tưởng nào cần làm với các BOM? – Mehrdad

+1

@Lambert, tôi khuyên bạn nên sử dụng read() vì nó sẽ không thực hiện bất kỳ xác nhận nào, nhưng bạn có thể tự mình thực hiện và không đọc tệp trong nhiều lần. Đối với BOM bạn có thể truyền đến ubyte và so sánh các byte đầu tiên, sau đó thực hiện một dàn diễn viên cho phần còn lại của slice ... –

+0

Hm ... không phải là giải pháp mà tôi đã hy vọng (tôi không muốn kiểm tra thủ công BOM) nhưng nó không quá tệ, tôi đoán; cảm ơn. – Mehrdad

4

Như để đối phó với việc kiểm tra BOM:

char[] ConvertViaBOM(ubyte[] data) { 
    char[] UTF8() { /*...*/ } 
    char[] UTF16LE(){ /*...*/ } 
    char[] UTF16BE(){ /*...*/ } 
    char[] UTF32LE(){ /*...*/ } 
    char[] UTF32BE(){ /*...*/ } 

    switch (data.length) { 
    default: 
    case 4: 
     if (data[0..4] == [cast(ubyte)0x00, 0x00, 0xFE, 0xFF]) return UTF32BE(); 
     if (data[0..4] == [cast(ubyte)0xFF, 0xFE, 0x00, 0x00]) return UTF32LE(); 
     goto case 3; 

    case 3: 
     if (data[0..3] == [cast(ubyte)0xEF, 0xBB, 0xBF]) return UTF8(); 
     goto case 2; 

    case 2: 
     if (data[0..2] == [cast(ubyte)0xFE, 0xFF]) return UTF16BE(); 
     if (data[0..2] == [cast(ubyte)0xFF, 0xFE]) return UTF16LE(); 
     goto case 1; 

    case 1: 
     return UTF8(); 
    } 
} 

thêm mơ hồ hơn BOM của là trái như một bài tập cho người đọc.

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