为什么将“€”解码为“€”也会在输出中将“é”变成“É”?

Why does decoding "€" to "€" also turn "é" into "é" in output?

我是 Perl 脚本的新手,在解码字符串时遇到了一些问题:

use HTML::Entities;
my $string='Rémunération   €';
$string=decode_entitie($string);
print "$string";

我得到的输出看起来像 Rémunération €,但它应该像 Rémunération €

谁能帮我解决这个问题?

如果您在终端上 运行 此版本的代码(修复了 decode_entities 中的拼写错误,启用了 strict mode and warnings,并添加了一个额外的 print):

use strict;
use warnings;    
use HTML::Entities;
my $string='Rémunération   €';
print "$string\n";
$string=decode_entities($string);
print "$string\n";

您应该看到以下输出:

Rémunération   €
Wide character in print at test.pl line 7.
Rémunération   €

发生以下事件链:

  1. 您的代码是用 UTF-8 编写的,但其中没有 use utf8;,因此 Perl 正在解析您的源代码(尤其是其中的任何字符串文字) 逐字节。因此,字符串文字 'é' 被解析为 双字符 字符串,因为 é 的 UTF-8 编码占用两个字节。

  2. 通常,这无关紧要(很多),因为你的 STDOUT 也不是 UTF-8 模式,所以它只需要你给它的任何字节字符串并吐出它逐字节输出,然后您的终端将结果输出解释为 UTF-8(或尝试)。

    所以,当你这样做时 print 'é'; Perl 认为你正在以字节模式打印一个两个字符的字符串,并写出两个字节,它们恰好构成了单个字符串的 UTF-8 编码字符 é.

  3. 但是,当您通过 decode_entities() 运行 字符串时,它会将 € 解码为实际的 Unicode 字符,这不会适合单个字节。

  4. 当您尝试打印结果字符串时,Perl 会注意到 "wide" 字符。它不能将其打印为单个字节,因此,它会回退到将 整个字符串 编码为 UTF-8(并发出警告,如果您启用了这些,就像您应该)。但这会导致 és(已经编码,因为 Perl 在解析您的代码时从未对它们进行解码)进行双 UTF8 编码,从而产生您看到的 mojibake 输出。

一个简单的修复方法是将 use utf8; 添加到您的代码中,并将 set all your filehandles(包括 STDIN / STDOUT / STDERR)添加到 UTF-默认为 8 模式,例如像这样:

use utf8;
use open qw(:std :utf8);

将这些行添加到上面的测试脚本中,您得到的输出应该是:

Rémunération   €
Rémunération   €