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

时间:2015-03-25 07:13:10

标签: perl utf-8 character-encoding

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

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

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

有人可以帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:8)

如果您运行此版本的代码(在decode_entities修复了错误,strict模式并启用了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编码{ {1}}。

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

  4. 当您尝试打印生成的字符串时,Perl会注意到“宽”字符。它无法将其打印为单个字节,因此它会回退到将整个字符串编码为UTF-8(并发出警告,如果您启用了这些,则应该如此)。但是这会导致 s(已经编码,因为Perl在解析代码时从未对其进行解码)以获得双UTF8编码,从而生成您看到的mojibake输出。

    < / LI>

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

    STDERR

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

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