相同的代码,不同机器上有关UTF8字符的不同结果

Tud*_*tin 3 perl utf-8

我有这个代码:

use strict;
use warnings;
use utf8;
use HTML::Entities;
use feature 'say';

binmode STDOUT, ':encoding(utf-8)';

my $t1 = "Česká Spořitelna - Q3 2014";
my $t2 =  "Česká Spořitelna - Q3 2014";

say decode_entities($t1);
say decode_entities($t2);
Run Code Online (Sandbox Code Playgroud)

在我的开发机器上执行时输出:

?eská Spo?itelna - Q3 2014
?eská Spo?itelna - Q3 2014
Run Code Online (Sandbox Code Playgroud)

当在UAT机器上执行(Aser Acceptance Test)时,输出:

Äeská SpoÅitelna - Q3 2014
Äeská SpoÅitelna - Q3 2014
Run Code Online (Sandbox Code Playgroud)

现在,在两台机器上,当我运行时,perl -v我们有这是为x86_64-linux-thread-multi-ld构建的perl 5,版本16,subversion 3(v5.16.3)

并且HTML::Entities两台机器上的版本相同:

    Installed: 3.69
    CPAN:      3.69  up to date
Run Code Online (Sandbox Code Playgroud)

我的开发机器运行CentOS release 5.8 (Final),UAT机器运行Red Hat Enterprise Linux Server release 5.8 (Tikanga)

编辑(关于locale命令的输出)它的输出在两台机器上是相同的:

LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
Run Code Online (Sandbox Code Playgroud)

更新:

我在facebook 上的perl开发者小组发布了这个问题的链接,并从那里得到了一些非常有用的想法:比较两个系统上的输出字节.如果它们相同,那就是显示问题.他们是.现在,有多种方法可以做到:

1)

say join ':', map { ord } split //, decode_entities($t1);
say join ':', map { ord } split //, decode_entities($t2);
Run Code Online (Sandbox Code Playgroud)

它显示268:101:115:107:225:32:83:112:111:345:105:116:101:108:110:97:32:45:32:81:51:32:50:48:49:52在两个系统上,因此,字节是相同的

2)打印$t1$t2输出到每个系统上的文件,然后hexdump -C针对这些文件运行并比较输出.此方法还显示文件的内容相同

结论

这是一个显示问题 - 控制台(putty)没有正确显示字符.当我们在数据库中添加这些字符时,我们遇到了这个问题,我认为我设法用上面的代码隔离它.你的答案(以及fb中的一些)帮助我找到了decode_entities()预期的工作,我们的问题在于其他地方(很可能在mysql表charset或mysql连接).

Bor*_*din 6

命令终端期望的编码是不同的.如果要打印UTF-8,则必须将两个终端设置为期望UTF-8,例如罗马尼亚语

LANG=ro_RO.UTF-8
Run Code Online (Sandbox Code Playgroud)

例如,设置STDOUT为在Perl中以这种方式编码输出

binmode STDOUT, ':encoding(utf-8)'
Run Code Online (Sandbox Code Playgroud)

更新

我可以解释发生了什么,虽然这就是为什么我不确定.

取字符串的第一个字符:"\x{010C}"这是一个大写的C caron.这是由Perl编码为两个八位字节代码"\x{C4}\x{8C}"并发送到终端,终端在您的开发机器上解码并正确显示它.

但是,在您的测试机器上,终端正在解码编码字符的第一个八位字节C4- 就好像它是ISO-8859-1,一个资本A变音符号.第二个八位字节 - 8C- 被忽略,因为它在该编码中是无效字符.

因此,您需要更改终端正在使用的代码页.这样做的方法是LANG按照我的描述进行设置,但如果您的语言环境设置正确,我无法解释为什么它不起作用.