2010-05-22 15 views
7

Si puedo abrir un archivo (y especifique una codificación directa):¿Cómo puedo decodificar datos UTF-16 en Perl cuando no conozco el orden de bytes?

open(my $file,"<:encoding(UTF-16)","some.file") || die "error $!\n"; 
while(<$file>) { 
    print "$_\n"; 
} 
close($file); 

que puede leer el contenido del archivo muy bien. Sin embargo, si lo hago:

use Encode; 

open(my $file,"some.file") || die "error $!\n"; 
while(<$file>) { 
    print decode("UTF-16",$_); 
} 
close($file); 

me sale el siguiente error:

UTF-16:Unrecognised BOM d at F:/Perl/lib/Encode.pm line 174 

¿Cómo puedo hacer que funcione con decode?

EDIT: aquí están los primeros bytes:

FF FE 3C 00 68 00 74 00 
+1

¿Nos un volcado de los primeros bytes del archivo que mostrar? –

+1

Ah, entonces tienes una lista de materiales. –

Respuesta

12

Si simplemente especifica "UTF-16", Perl buscará la marca de orden de bytes (BOM) para descubrir cómo analizarla. Si no hay una lista de materiales, va a explotar. En ese caso, debe decirle a Encode qué orden de bytes tiene especificando "UTF-16LE" para little-endian o "UTF-16BE" para big-endian.

Sin embargo, está pasando algo más con su situación, pero es difícil de decir sin ver los datos que tiene en el archivo. Me sale el mismo error con ambos fragmentos. Si no tengo una lista de materiales y no especifico un orden de bytes, mi Perl se queja de cualquier manera. ¿Qué Perl estás usando y qué plataforma tienes? ¿Su plataforma tiene la endianidad nativa de su archivo? Creo que el comportamiento que veo es correcto según los documentos.

Además, no puede simplemente leer una línea en una codificación desconocida (cualquiera que sea el valor por defecto de Perl) y enviarla a decode. Puede terminar en el medio de una secuencia de múltiples bytes. Usted tiene que utilizar Encode::FB_QUIET para guardar la parte de la memoria intermedia que no se podía decodificar y añadir que al siguiente fragmento de datos:

open my($lefh), '<:raw', 'text-utf16.txt'; 

my $string; 
while($string .= <$lefh>) { 
    print decode("UTF-16LE", $string, Encode::FB_QUIET) 
    } 
+0

Ya sabes, si concateno las cadenas en un búfer grande, puedo usar la decodificación con éxito. – Geo

+3

Puede decodificar todo de una vez porque ve la lista de materiales para toda la cadena. Romperlo en líneas individuales significa que la lista de materiales es solo para el primer fragmento. Encode no hace nada especial para tratar de adivinar que una cadena está de alguna manera relacionada con otra. –

1

Lo que estás tratando de hacer imposible.

Usted está leyendo líneas de texto sin especificar una codificación, por lo que cada byte que contiene un carácter de nueva línea (por defecto \x0a) termina una línea. Pero este carácter de nueva línea puede estar en el medio de un carácter UTF-16, en cuyo caso su siguiente línea no puede decodificarse. Si sus datos son UTF-16LE, esto sucederá todo el tiempo: los feeds de línea son \x0a \x00. Si tiene UTF16-BE, puede tener suerte (las nuevas líneas son \x00 \x0a), hasta que obtenga un carácter con \x0a en el byte alto.

Por lo tanto, no haga eso, abra el archivo con la codificación correcta.

+0

¿Qué sucede si no siempre tiene un archivo y solo le pasan una cadena? – Geo

+0

No es imposible: vea mi respuesta sobre cómo debe manejar las secuencias incompletas de bytes. –

Cuestiones relacionadas