2011-01-17 13 views
8

¿Existe alguna forma de "un tamaño para todos" (más o menos) para leer un archivo de texto en D?Leer archivo de texto en D

El requisito es que la función detecte automáticamente la codificación y me proporcione todos los datos del archivo en un formato coherente, como string o dstring. Debe detectar automáticamente las listas de materiales e interpretarlas según corresponda.

Intenté std.file.readText() pero no maneja bien las diferentes codificaciones.

(Por supuesto, esto tendrá una tasa de fracaso no es cero, y eso es aceptable para mi aplicación.)

Respuesta

8

Creo que las únicas opciones reales de archivo de E/S en Fobos en este punto (aparte de llamando a las funciones C) son std.file.readText y std.stdio.File. readText leerá en un archivo como una matriz de caracteres, wchars o dchars (de forma predeterminada es inmutable (char) [] - es decir, cadena). Creo que la codificación debe ser UTF-8, UTF-16 y UTF-32 para chars, wchars y dchars, respectivamente, aunque tendré que ir a profundizar en el código fuente para estar seguro. Cualquier codificación que sea compatible con esas codificaciones (por ejemplo, ASCII es compatible con UTF-8) debería funcionar bien.

Si usa File, tiene varias opciones para leer el archivo, incluyendo readln y rawRead. Sin embargo, esencialmente lee el archivo usando una codificación compatible con UTF-8, UTF-16 o UTF-32, como con readText, o lo lee como datos binarios y lo manipula usted mismo.

Dado que, los tipos de caracteres en D son char, wchar y dchar, que son unidades de código UTF-8, UTF-16 y UTF-32, respectivamente, a menos que desee leer los datos en formato binario, el archivo va a tener que codificarse en una codificación compatible con uno de esos tres tipos de Unicode. Dada una cadena en una codificación particular, puede convertirla a otra codificación usando las funciones en std.utf. Sin embargo, no conozco ninguna forma de consultar un archivo para su tipo de codificación que no sea usar readText para tratar de leer el archivo en una codificación dada y ver si tiene éxito.

Por lo tanto, a menos que desee procesar un archivo usted mismo y determinar sobre la marcha qué codificación contiene, su mejor opción es simplemente usar readText con cada tipo de cadena consecutiva, utilizando la primera que tenga éxito. Sin embargo, dado que los archivos de texto normalmente están en UTF-8 o en una codificación compatible con UTF-8, esperaría que readText utilizado con una cadena normal casi siempre funcionaría bien.

+0

Hm ... alguna idea de qué hacer con las listas de materiales? – Mehrdad

+1

@Lambert, recomiendo usar read() ya que no hará ninguna validación, pero puede hacerlo usted mismo y no está leyendo el archivo varias veces. Para la BOM puedes convertir a ubyte y comparar los primeros bytes, luego hacer un molde para el resto del segmento ... –

+0

Hm ... no era la solución que esperaba (no quería verificar manualmente la lista de materiales)) pero no es tan malo, supongo; Gracias. – Mehrdad

4

cuanto a tratar con el control de la lista de materiales:

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

la adición de más oscura de la lista de materiales se deja como ejercicio para el lector.

Cuestiones relacionadas