我正在尝试区分使用Encode::decode("utf8", $var)
和utf8::decode($var)
之间的差异,结果很有趣。我已经发现多次调用前者会导致错误“Cannot decode string with wide characters at...”,而后者方法将愉快地运行多次,只返回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标志: Unicode: 195 168 194 171 194 139 10 十六进制: c3a8c2abc28b0a ============== 长度:4 utf8标志:1 Unicode: 232 171 139 10 十六进制: c3a8c2abc28b0a ============== 长度:2 utf8标志:1 Unicode: 35531 10 十六进制: e8ab8b0a这是我所期望的。长度最初为7,因为perl认为$test只是一系列字节。解码一次后,perl知道$test是一系列以utf8编码的字符(即使$test在内存中仍然是7个字节,perl返回4个字符的长度而不是7个字节)。第二次解码后,$test包含4个字节,被解释为2个字符,这正是我所期望的,因为Encode::decode将4个代码点解释为utf8编码的字节,结果是2个字符。奇怪的是,当我修改代码调用utf8::decode时(将所有$test = Encode::decode("utf8", $test);替换为utf8::decode($test))。
这几乎产生相同的输出,只有长度的结果不同:
长度:7 utf8标志: Unicode: 195 168 194 171 194 139 10 十六进制: c3a8c2abc28b0a ============== 长度:4 utf8标志:1 Unicode: 232 171 139 10 十六进制: c3a8c2abc28b0a ============== 长度:4 utf8标志:1 Unicode: 35531 10 十六进制: e8ab8b0a看起来perl首先计算解码前的字节数(如预期),然后在第一次解码后计算字符数,但在第二次解码后再次计算字节数(这不是预期的)。为什么会发生这种转换?我对这些解码函数的工作方式理解有误吗?
谢谢, Matt
require
而不是use
来引入模块? - Eric Strom