Как я могу декодировать данные UTF-16 в Perl, когда я не знаю порядок байтов?

если я открываю файл (и указываю кодировку напрямую):

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

Я могу хорошо прочитать содержимое файла. Однако, если я это сделаю:

use Encode;

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

я получаю следующую ошибку:

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

как я могу заставить его работать с decode?

EDIT: вот первые несколько байтов:

FF FE 3C 00 68 00 74 00

3 ответов


Если вы просто укажете "UTF-16", Perl будет искать метку порядка байтов (BOM), чтобы выяснить, как ее анализировать. Если нет бомбы, она взорвется. В этом случае вы должны сообщить, какой порядок байтов у вас есть, указав "UTF-16LE" для little-endian или "UTF-16BE" для big-endian.

в вашей ситуации происходит что-то еще, но трудно сказать, не видя данных, которые у вас есть в файле. Я получаю ту же ошибку с обоими фрагментами. Если у меня нет спецификации, и я не указываю порядок байтов, мой Perl жалуется в любом случае. Какой Perl вы используете и какая платформа у вас есть? Имеет ли ваша платформа собственную endianness вашего файла? Я думаю, что поведение, которое я вижу, правильно в соответствии с документами.

кроме того, вы не можете просто прочитать строку в неизвестной кодировке (независимо от значения по умолчанию Perl), а затем отправить ее в decode. Вы можете оказаться в середине многобайтовой последовательности. Вы должны использовать Encode::FB_QUIET сохранить часть буфера, которую вы не смогли декодировать и добавить к следующему фрагменту данных:

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

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

необходимо указать UTF-16BE или UTF-16LE. См.http://perldoc.perl.org/Encode/Unicode.html#Size%2c-Endianness%2c-and-BOM


то, что вы пытаетесь сделать невозможно.

Вы читаете строки текста без указания кодировки, поэтому каждый байт, содержащий символ новой строки (по умолчанию \x0a) концах линии. Но этот символ новой строки может быть в середине символа UTF-16, и в этом случае ваша следующая строка не может быть декодирована. Если ваши данные UTF-16LE, это произойдет все каналы временной линии \x0a \x00. Если у вас есть UTF16-BE, вам может повезти (новые строки \x00 \x0a), пока вы не получите символ с \x0a в старшем байте.

итак, не делайте этого, откройте файл в правильной кодировке.