当我不知道字节顺序时,如何在Perl中解码UTF-16数据?

7

如果我打开一个文件(并直接指定编码):

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

1
你能给我们展示一下该文件的前几个字节的转储吗? - brian d foy
3个回答

12
如果你只是简单地指定 "UTF-16",Perl 会查找字节顺序标记 (BOM) 来确定如何解析它。如果没有 BOM,则会出现错误。在这种情况下,你必须告诉 Encode 你拥有的字节顺序,通过指定 "UTF-16LE" 表示小端或 "UTF-16BE" 表示大端。

不过,在你的情况中还有其他问题,但是没有看到文件中的数据很难判断。我用两个代码片段都遇到了相同的错误。如果我既没有 BOM,也没有指定字节顺序,我的 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) 
    }

你知道吗,如果我将字符串连接成一个大缓冲区,我就可以成功地对其进行解码。 - Geo
3
因为它看到了整个字符串的BOM,所以你可以一次解码整个字符串。将其分成单独的行意味着BOM仅适用于第一个块。编码不会特别处理以猜测一个字符串与另一个字符串有关联的情况。 - brian d foy

5

1

你试图做的事情是不可能的。

你正在阅读没有指定编码的文本,因此每个包含换行符(默认为\x0a)的字节都会结束一行。但是这个换行符很可能在一个UTF-16字符的中间,这样你的下一行就无法解码。 如果你的数据是UTF-16LE,这种情况将经常发生 - 换行符是\x0a \x00。如果你有UTF16-BE,你可能会走运(换行符是\x00 \x0a),直到你得到一个高字节带有\x0a的字符。

所以,不要这样做,在正确的编码下打开文件。


如果你并不总是有一个文件,而只是传递了一个字符串,那该怎么办? - Geo
这并非不可能:请查看我的答案,了解如何处理不完整的字节序列。 - brian d foy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接