2011-01-17 14 views
8

Esiste un modo per la lettura di un file di testo in D in un'unica soluzione (più o meno)?Leggi file di testo in D

Il requisito è che la funzione rilevi automaticamente la codifica e mi dia i dati completi del file in un formato coerente, ad esempio string o dstring. Dovrebbe auto-rilevare le distinte materiali e interpretarle come appropriato.

Ho provato std.file.readText() ma non gestisce bene codifiche diverse.

(Naturalmente, questo avrà un diverso da zero tasso di fallimento, e questo è accettabile per la mia applicazione.)

risposta

8

Credo che le uniche opzioni reali per file di I/O in Phobos a questo punto (a parte chiamando le funzioni C) sono std.file.readText e std.stdio.File. readText leggerà in un file come una matrice di caratteri, wchars o dchars (per impostazione predefinita a immutable (char) [] - i.e. stringa). Credo che la codifica deve essere UTF-8, UTF-16 e UTF-32 rispettivamente per char, wchars e dchar, anche se dovrei andare a scavare nel codice sorgente per essere sicuro. Qualsiasi codifica compatibile con tali codifiche (ad esempio ASCII è compatibile con UTF-8) dovrebbe funzionare correttamente.

Se si utilizza File, allora si hanno diverse opzioni per le funzioni di leggere il file con - tra cui readln e rawRead. Tuttavia, in pratica si legge il file utilizzando una codifica UTF-8, UTF-16 o UTF-32 compatibile come con lo readText, oppure lo si legge come dati binari e lo si manipola da soli.

Poiché, i tipi di carattere in D sono char, wchar e dchar, che sono rispettivamente unità di codice UTF-8, UTF-16 e UTF-32, a meno che non si desideri leggere i dati in formato binario, il file sta per essere codificato in una codifica compatibile con uno di questi tre tipi di Unicode. Data una stringa in una particolare codifica, è possibile convertirla in un'altra codifica utilizzando le funzioni in std.utf. Tuttavia, non sono a conoscenza di alcun modo per interrogare un file per il suo tipo di codifica diverso dall'uso di readText per provare a leggere il file in una determinata codifica e vedere se ha esito positivo.

Quindi, a meno che tu non voglia elaborare un file tu stesso e determinare al volo quale codifica sia, la soluzione migliore è probabilmente usare semplicemente readText con ogni tipo di stringa consecutivo, utilizzando il primo che riesce. Tuttavia, poiché i file di testo sono normalmente in codifica UTF-8 o UTF-8, mi aspetto che lo readText utilizzato con una stringa normale funzioni quasi sempre alla perfezione.

+0

Hm ... qualche idea su cosa fare con le BOM? – Mehrdad

+1

@Lambert, suggerisco caldamente di usare read() in quanto non esegue alcuna convalida, ma puoi farlo tu stesso e non stai leggendo il file più volte. Per la distinta base è possibile eseguire il cast per ubyte e confrontare i primi byte, quindi eseguire un cast per il resto della sezione ... –

+0

Hm ... non la soluzione che speravo (non volevo controllare manualmente la distinta base) ma non è troppo male, credo; Grazie. – Mehrdad

4

Quanto a che fare con il controllo del 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(); 
    } 
} 

aggiunta più oscura BOM è lasciata come esercizio per il lettore.