Как я могу декодировать данные 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?

РЕДАКТИРОВАТЬ: вот первые несколько байтов:

FF FE 3C 00 68 00 74 00

3 ответа

Решение

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

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

Кроме того, вы не можете просто прочитать строку в какой-то неизвестной кодировке (какой бы ни была настройка по умолчанию в 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

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

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

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

Другие вопросы по тегам