以下脚本以UTF-8编码:
use utf8;
$fuer = pack('H*', '66c3bc72');
$fuer =~ s/ü/!!!/;
print $fuer;
ü
中的s///
作为c3 bc
存储在脚本中,如下面的xxd
十六进制转储所示。
0000000: 75 73 65 20 75 74 66 38 3b 0a 0a 24 66 75 65 72 use utf8;..$fuer
0000010: 20 3d 20 70 61 63 6b 28 27 48 2a 27 2c 20 27 36 = pack('H*', '6
0000020: 36 63 33 62 63 37 32 27 29 3b 0a 0a 24 66 75 65 6c3bc72');..$fue
0000030: 72 20 3d 7e 20 73 2f c3 bc 2f 21 21 21 2f 3b 0a r =~ s/../!!!/;.
0000040: 0a 70 72 69 6e 74 20 24 66 75 65 72 3b 0a .print $fuer;.
c3 bc
是ü
的UTF-8表示。
由于脚本是以UTF-8编码的,而我是use
utf8
,我希望脚本替换变量für
中的$fuer
- 但它没有。
但是,如果我删除了use utf8
。这与我认为use utf8
的目的相反:表示脚本是以UTF-8编码的。
答案 0 :(得分:9)
问题在于字符边界。您正在将编码的字节字符串与已解码的字符串进行比较
$fuer = pack('H*', '66c3bc72')
创建四字节字符串"\x66\xc3\xbc\x72"
,而带有分音ü
的小u则为"\xfc"
,因此两者不匹配
如果您使用decode_utf8
模块中的Encode
来进一步处理变量$fuer
,那么它会解码UTF-8以形成三个字符的字符串"\x66\xfc\x72"
,然后替代品将起作用
use utf8
将等效的decode_utf8
应用于整个源文件,因此如果没有ü
,则"\xc3\xbc"
会将编码显示为bash
,打包变量
答案 1 :(得分:4)
让我们将ü
移出s///
并移出自己的变量,以便我们检查它。
use utf8; # Script is encoded using UTF-8
use open ':std', ':encoding(UTF-8)'; # Terminal expects UTF-8.
use strict;
use warnings;
my $uuml = "ü";
printf("%d %vX %s", length($uuml), $uuml, $uuml); # 1 FC ü
my $fuer = pack('H*', '66c3bc72');
printf("%d %vX %s", length($fuer), $fuer, $fuer); # 4 66.C3.BC.72 für
$fuer =~ s/\Q$uuml/!!!/;
printf("%d %vX %s", length($fuer), $fuer, $fuer); # 4 66.C3.BC.72 für
这很明显,您将ü
(FC
)的Unicode代码点与ü
(C3 BC
)的UTF-8编码进行比较。
所以是的,use utf8;
表示脚本是使用UTF-8编码的......但它确实可以让Perl正确解码脚本。
解码所有输入并对所有输出进行编码!解决方案是替换
my $fuer = pack('H*', '66c3bc72');
与
use Encode qw( decode_utf8 );
my $fuer = decode_utf8(pack('H*', '66c3bc72'));
或
my $fuer = pack('H*', '66c3bc72');
utf8::decode($fuer);