如果我运行以下 Perl 程序:
perl -e 'use utf8; print "鸡\n";'
我收到这个警告:
Wide character in print at -e line 1.
如果我运行这个 Perl 程序:
perl -e 'print "鸡\n";'
我没有收到警告。
我认为需要 use utf8
才能在 Perl 脚本中使用 UTF-8 字符。为什么这不起作用,我该如何解决?我正在使用 Perl 5.16.2。如果这是在文件中而不是在命令行上的一个衬里,我会遇到同样的问题。
如果没有 use utf8
,Perl 会将您的字符串解释为单字节字符序列。如您所见,您的字符串中有四个字节:
$ perl -E 'say join ":", map { ord } split //, "鸡\n";'
233:184:161:10
前三个字节组成你的字符,最后一个是换行符。
对 print
的调用将这四个字符发送到 STDOUT。然后,您的控制台会计算出如何显示这些字符。如果您的控制台设置为使用 UTF8,那么它将这三个字节解释为您的单个字符,这就是显示的内容。
如果我们添加 utf8
模块,情况就不同了。在这种情况下,Perl 将您的字符串解释为两个字符。
$ perl -Mutf8 -E 'say join ":", map { ord } split //, "鸡\n";'
40481:10
默认情况下,Perl 的 IO 层假定它使用单字节字符。所以当你试图打印一个多字节字符时,Perl 认为有问题并给你一个警告。与以往一样,您可以通过包含 use diagnostics
获得有关此错误的更多解释。它会这样说:
(S utf8) Perl 遇到了一个宽字符 (>255),但它没有预料到它。此警告默认为 I/O(如打印)打开。消除此警告的最简单方法是将 :utf8 层添加到输出中,例如 binmode STDOUT, ':utf8'。另一种关闭警告的方法是添加 no warnings 'utf8';但这通常更接近作弊。通常,您应该使用编码显式标记文件句柄,请参阅 open 和 perlfunc/binmode。
正如其他人指出的那样,您需要告诉 Perl 接受多字节输出。有很多方法可以做到这一点(有关一些示例,请参阅 Perl Unicode Tutorial)。最简单的方法之一是使用 -CS
命令行标志 - 它告诉三个标准文件句柄(STDIN、STDOUT 和 STDERR)来处理 UTF8。
$ perl -Mutf8 -e 'print "鸡\n";'
Wide character in print at -e line 1.
鸡
对比
$ perl -Mutf8 -CS -e 'print "鸡\n";'
鸡
Unicode 是一个大而复杂的领域。正如您所看到的,许多简单的程序似乎都在做正确的事情,但原因却是错误的。当您开始修复程序的一部分时,事情通常会变得更糟,直到您修复了所有程序。
use utf8;
所做的只是告诉 Perl 源代码是使用 UTF-8 编码的。你需要告诉 Perl 如何编码你的文本:
use open ':std', ':encoding(UTF-8)';
将所有标准输出编码为 UTF-8:
binmode STDOUT, ":utf8";
use open ':std', ':encoding(UTF-8)';
正如另一个答案所建议的那样,它对 STDOUT 执行此操作,但也将 STDERR 和 STDIN 标记为 UTF-8,因此您以一个语句的价格获得三个。另请参阅stackoverflow.com/a/42194059
BEGIN {binmode STDOUT, ":utf8";} print "\x{201C}in curly quotes\x{201D}\n";
通过使用 CPAN 模块 utf8::all
,您可以接近“在任何地方都使用 utf8”。
perl -Mutf8::all -e 'print "鸡\n";'
当 print
收到无法打印的内容(未提供 :encoding
层时字符大于 255)时,它假定您打算使用 UTF-8 对其进行编码。在对问题发出警告后,它会这样做。
在西班牙语中,除了开始使用之外,您还会发现此错误:
use utf8;
您的编辑器编码采用不同的编码。所以你在编辑器上看到的并不是 Perl 所做的。要解决该错误,只需将编辑器编码更改为 Unicode/UTF-8。
-Mutf8
?use utf8;