2010-05-22 6 views
7

Se apro un file (e specificare direttamente una codifica):Come posso decodificare i dati UTF-16 in Perl quando non conosco l'ordine dei byte?

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

riesco a leggere il contenuto del file piacevolmente. Tuttavia, se faccio:

use Encode; 

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

ottengo il seguente errore:

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

Come faccio a farlo funzionare con decode?

EDIT: ecco i primi diversi byte:

FF FE 3C 00 68 00 74 00 
+1

può noi una discarica dei primi diversi byte di tale file mostrare? –

+1

Ah, quindi hai una BOM. –

risposta

12

Se si specifica semplicemente "UTF-16", Perl cercherà il byte-order mark (BOM) per capire come analizzarlo. Se non c'è BOM, esploderà. In tal caso, devi dire a Encode quale ordine di byte hai specificato specificando "UTF-16LE" per little-endian o "UTF-16BE" per big-endian.

C'è qualcos'altro, ma è difficile dirlo senza vedere i dati presenti nel file. Ottengo lo stesso errore con entrambi gli snippet. Se non ho una distinta base e non specificano un ordine in byte, il mio Perl si lamenta in entrambi i casi. Quale Perl stai usando e quale piattaforma hai? La tua piattaforma ha il carattere nativo del tuo file? Penso che il comportamento che vedo sia corretto secondo i documenti.

Inoltre, non è possibile leggere semplicemente una riga in qualche codifica sconosciuta (qualunque sia l'impostazione predefinita di Perl) quindi spedirla a decode. Potresti finire nel mezzo di una sequenza multi-byte. Devi usare Encode::FB_QUIET per salvare la parte del buffer che non si poteva decodificare e aggiungere che, per il prossimo blocco di dati:

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

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

Sapete, se concatenare le stringhe in un unico buffer di grandi dimensioni, posso utilizzare la decodifica su di esso con successo. – Geo

+3

Puoi decodificare tutto in una volta perché vede la distinta base per l'intera stringa. Spezzarlo in singole righe significa che la distinta base è solo per il primo pezzo. La codifica non fa nulla di speciale per cercare di indovinare che una stringa è in qualche modo correlata a un'altra. –

1

Quello che stai cercando di fare impossibile.

Stai leggendo righe di testo senza specificare una codifica, quindi ogni byte che contiene un carattere di nuova riga (predefinito \x0a) termina una riga. Ma questo carattere di nuova riga potrebbe benissimo essere nel mezzo di un carattere UTF-16, nel qual caso la tua prossima riga non può essere decodificata. Se i tuoi dati sono UTF-16LE, ciò avverrà ininterrottamente: lo stato della linea è \x0a \x00. Se disponi di UTF16-BE, potresti essere fortunato (i nuovi numeri sono \x00 \x0a), finché non ottieni un personaggio con \x0a nel byte alto.

Quindi, non farlo, apri il file nella giusta codifica.

+0

Cosa succede se non si dispone sempre di un file e si ottiene solo una stringa? – Geo

+0

Non è impossibile: vedi la mia risposta su come dovresti gestire sequenze di byte incomplete. –

Problemi correlati