我有一些有趣的结果,试图辨别使用Encode::decode("utf8", $var)
和之间的区别utf8::decode($var)
。我已经发现,在一个变量上多次调用前者最终会导致错误“无法在...处解码带有宽字符的字符串”,而后一种方法会很高兴地运行任意多次,只是返回 false。
我无法理解的是length
函数如何根据您用于解码的方法返回不同的结果。出现问题是因为我正在处理来自外部文件的“双重编码”utf8 文本。为了演示这个问题,我创建了一个文本文件“test.txt”,其中一行包含以下 Unicode 字符:U+00e8、U+00ab、U+0086、U+000a。这些 Unicode 字符是 Unicode 字符 U+8acb 和换行符的双重编码。该文件以 UTF8 编码到磁盘。然后我运行以下 perl 脚本:
#!/usr/bin/perl
use strict;
use warnings;
require "Encode.pm";
require "utf8.pm";
open FILE, "test.txt" or die $!;
my @lines = <FILE>;
my $test = $lines[0];
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
my @unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
my @hex = (unpack('H*', $test));
print "Hex:\n@hex\n";
print "==============\n";
$test = Encode::decode("utf8", $test);
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
@unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
@hex = (unpack('H*', $test));
print "Hex:\n@hex\n";
print "==============\n";
$test = Encode::decode("utf8", $test);
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
@unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
@hex = (unpack('H*', $test));
print "Hex:\n@hex\n";
这给出了以下输出:
长度:7 utf8 标志: 统一码: 195 168 194 171 194 139 10 十六进制: c3a8c2abc28b0a =============== 长度:4 UTF8 标志:1 统一码: 232 171 139 10 十六进制: c3a8c2abc28b0a =============== 长度:2 UTF8 标志:1 统一码: 35531 10 十六进制: e8ab8b0a
这是我所期望的。长度原来是 7,因为 perl 认为 $test 只是一系列字节。解码一次后,perl 知道 $test 是一系列 utf8 编码的字符(即 perl 不是返回 7 个字节的长度,而是返回 4 个字符的长度,即使 $test 在内存中仍然是 7 个字节)。在第二次解码之后,$test 包含解释为 2 个字符的 4 个字节,这是我所期望的,因为 Encode::decode 采用了 4 个代码点并将它们解释为 utf8 编码的字节,从而产生 2 个字符。奇怪的是,当我修改代码以调用 utf8::decode 时(将所有 $test = Encode::decode("utf8", $test); 替换为 utf8::decode($test))
这给出了几乎相同的输出,只是长度的结果不同:
长度:7 utf8 标志: 统一码: 195 168 194 171 194 139 10 十六进制: c3a8c2abc28b0a =============== 长度:4 UTF8 标志:1 统一码: 232 171 139 10 十六进制: c3a8c2abc28b0a =============== 长度:4 UTF8 标志:1 统一码: 35531 10 十六进制: e8ab8b0a
似乎 perl 在解码前首先计算字节数(如预期的那样),然后在第一次解码后计算字符数,然后在第二次解码后再次计算字节数(不是预期的)。为什么会发生这种转变?我对这些解码功能如何工作的理解有偏差吗?
谢谢,
马特