2010-05-22 1 views
7

Если я открываю файл (и указать кодировку непосредственно):Как я могу декодировать данные 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 
+1

Можете ли вы показать нам дамп первых нескольких байтов этого файла? –

+1

Ах, у вас есть спецификация. –

ответ

12

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

Однако, что-то происходит с вашей ситуацией, но это трудно сказать, не видя данных, которые у вас есть в файле. Я получаю ту же ошибку с обоими фрагментами. Если у меня нет спецификации и я не указываю порядок байтов, мой 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) 
    } 
+0

Знаете, если я объединю строки в один большой буфер, я могу успешно использовать декодирование на нем. – Geo

+3

Вы можете декодировать все это сразу, потому что он видит спецификацию для всей строки. Разбивание его на отдельные строки означает, что спецификация предназначена только для первого фрагмента. Encode не делает ничего особенного, чтобы попытаться угадать, что одна строка каким-то образом связана с другим. –

1

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

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

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

+0

Что делать, если у вас не всегда есть файл, и вы получаете только строку? – Geo

+0

Это не невозможно: см. Мой ответ, как вы должны обрабатывать неполные последовательности байтов. –