使用“use utf8;”给了我“打印中的宽字符”

Use of 'use utf8;' gives me 'Wide character in print'

提问人:Eric Johnson 提问时间:3/5/2013 最后编辑:Peter MortensenEric Johnson 更新时间:2/27/2023 访问量:73081

问:

如果我运行以下 Perl 程序:

perl -e 'use utf8; print "鸡\n";'

我收到以下警告:

Wide character in print at -e line 1.

如果我运行这个 Perl 程序:

perl -e 'print "鸡\n";'

我没有收到警告。

我认为在 Perl 脚本中使用 UTF-8 字符是必需的。为什么这不起作用,我该如何解决?我正在使用 Perl 5.16.2。如果这是在文件中而不是命令行上的一行,我也有同样的问题。use utf8

Perl Unicode UTF-8

评论

4赞 hobbs 3/5/2013
“为什么这行不通?”它确实有效,但根据我对Unicode的经验,有很多非常破碎的程序看起来正在工作。当你修复一件事,使代码的错误稍微少一点时,结果似乎要糟糕得多。只有当你修复最后一部分时,一切才会再次恢复正常。

答:

84赞 ikegami 3/5/2013 #1

所有要做的就是告诉 Perl 源代码是使用 UTF-8 编码的。你需要告诉 Perl 如何对文本进行编码:use utf8;

use open ':std', ':encoding(UTF-8)';

评论

1赞 squirl 3/10/2016
谢谢,这适用于存储在文件中的程序,而不是命令行上的单行代码,@DaveCross的答案涵盖了这一点。
14赞 Joel Berger 3/5/2013 #2

您可以使用 CPAN 模块 utf8::all 接近“到处都做 utf8”。

perl -Mutf8::all -e 'print "鸡\n";'

当收到它无法打印的内容(未提供图层时大于 255 的字符)时,它会假定您打算使用 UTF-8 对其进行编码。在警告问题后,它会这样做。print:encoding

116赞 Dave Cross 3/5/2013 #3

Without Perl 将字符串解释为单字节字符序列。从中可以看出,字符串中有四个字节:use utf8

$ perl -E 'say join ":", map { ord } split //, "鸡\n";'
233:184:161:10

前三个字节组成您的字符,最后一个字节是换行符。

调用将这四个字符发送到 STDOUT。然后,您的控制台会计算出如何显示这些字符。如果您的控制台设置为使用 UTF8,那么它会将这三个字节解释为您的单个字符,这就是显示的内容。print

如果我们添加模块,情况就不同了。在这种情况下,Perl 将字符串解释为两个字符。utf8

$ 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'。关闭 warning 是不添加警告 'utf8';但这通常更接近 作弊。通常,您应该显式标记 File句柄,请参阅 Open 和 Perlfunc/binMode。

正如其他人所指出的,你需要告诉Perl接受多字节输出。有很多方法可以做到这一点(参见 Perl Unicode 教程中的一些示例)。最简单的方法之一是使用命令行标志 - 它告诉三个标准文件句柄(STDIN、STDOUT 和 STDERR)处理 UTF8。-CS

$ perl -Mutf8 -e 'print "鸡\n";'
Wide character in print at -e line 1.
鸡

$ perl -Mutf8 -CS -e 'print "鸡\n";'
鸡

Unicode是一个庞大而复杂的领域。正如你所看到的,许多简单的程序似乎在做正确的事情,但出于错误的原因。当您开始修复部分程序时,情况通常会变得更糟,直到您修复了所有程序。

评论

0赞 Lei Yang 2/20/2017
如果不是在一个行 perl 中,如何拼写?-Mutf8
0赞 Dave Cross 2/20/2017
@LeiYang:use utf8;
19赞 Boris Ivanov 2/18/2014 #4

将所有标准输出编码为 UTF-8:

binmode STDOUT, ":utf8";

评论

3赞 Stephen Ostermiller 2/26/2020
use open ':std', ':encoding(UTF-8)';正如另一个答案所建议的那样,STDOUT 会这样做,但也会将 STDERR 和 STDIN 标记为 UTF-8,因此您可以以一个语句的价格获得三个。另请参阅 stackoverflow.com/a/42194059
0赞 Boris Ivanov 2/26/2020
同意。这甚至更好。
0赞 grjash 3/16/2021
我无法让这个简单的程序在运行 Perl 10 的 Windows 5.32 PC 上正确打印大括号。是缺少什么,还是只是 Windows 做不到的另一件事?BEGIN {binmode STDOUT, ":utf8";} print "\x{201C}in curly quotes\x{201D}\n";
8赞 Karthikeyan.R.S 4/9/2015 #5

你可以用这个,

perl -CS filename.

它还将终止该错误。

参考资料(删节):

            The -C flag controls some of the Perl Unicode features.

            As of 5.8.1, the -C can be followed either by a number or a list of option letters.  The letters, their numeric values,
            and effects are as follows; listing the letters is equal to summing the numbers.

                I     1   STDIN is assumed to be in UTF-8
                O     2   STDOUT will be in UTF-8
                E     4   STDERR will be in UTF-8
                S     7   I + O + E

评论

0赞 roli 2/9/2022
如果您不只是在运行 Oneliner,请参阅此处:perldoc.perl.org/...
0赞 Sridhar Sarnobat 2/27/2023
与其他解决方案不同,此解决方案不需要检测库
-1赞 DiegoAr 5/23/2015 #6

在西班牙语中,您可以在开始使用时发现此错误:

use utf8;

编辑器编码采用不同的编码。所以你在编辑器上看到的不是Perl所做的。要解决该错误,只需将编辑器编码更改为 Unicode/UTF-8

评论

2赞 Dave Cross 7/28/2015
不。这不是导致错误的原因。代码全部正确编码为 UTF8,但输出文件句柄不知道它是。