我遇到类似于How can I properly align UTF-8 strings with Perl's printf?的问题:
我(Linux)系统的区域设置默认为LC_CTYPE=de_DE.UTF-8
,我编写了一个Perl程序(使用perl-5.26.1),该程序“不是”使用Unicode字符,而是使用ISO Latin-1字符集(例如°
)。
因此,我没有在Perl脚本中激活任何Unicode或语言环境功能。
“所有内容”似乎都可以正常运行,其中一个例外是:我正在使用printf
的{{1}}格式来对齐字符串,但这不能按预期工作。
在调试器中播放时,会出现以下现象:
%-10s
到目前为止看起来还不错...
DB<1> $s='X°X'
DB<2> printf("_%3s_\n", $s)
_X°X_
糟糕;那不是 DB<3> printf("_%4s_\n", $s)
_X°X_
吗?
"_ X°X_"
一个人掉吗?
DB<4> printf("_%5s_\n", $s)
_ X°X_
那不是 DB<5> x length($s)
0 4
吗?
3
DB<8> x ord($s[1])
0 0
DB<9> x $s
0 'X°X'
DB<10>
是否应编码为一个字节?我以为UTF-8会将未修改的Latin-1范围映射到Unicode。
所以可能的问题是:
发生了什么事?
这是Perl的错误吗?
如果没有,如何确定格式和字符串长度?
答案 0 :(得分:3)
UTF-8仅将ASCII范围(0..127)映射到1个字节。 Latin-1字符的范围是0..255; UTF-8 不能将它们全部映射到一个字节。如果是这样,将没有其他任何映射。
0到127之间的字符被编码为1个字节。
从128到2047的字符被编码为2个字节。
依此类推。
https://en.wikipedia.org/wiki/UTF-8
您需要在Perl脚本中使用use utf8;
和binmode STDOUT, ':encoding(UTF-8)';
(为了保持一致性,我对STDIN
和STDERR
进行了同样的操作:
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
BEGIN {
binmode STDIN, ':encoding(UTF-8)';
binmode STDOUT, ':encoding(UTF-8)';
binmode STDERR, ':encoding(UTF-8)';
}
printf "|%-10s|\n", "x";
printf "|%-10s|\n", "°";
输出正确对齐:
|x |
|° |
如果我注释掉use utf8;
或binmode STDOUT, ':encoding(UTF-8)';
,则输出未对齐和/或度数字符显示不正确。
引用perldoc utf8
(utf8
模块的文档):
“
use utf8
”指示编译器允许Perl解析器中的UTF-8 当前词法范围内的程序文本。
(这需要将输出设备或终端仿真器配置为显示UTF-8。)
答案 1 :(得分:2)
Perl代码必须使用ASCII(默认为{no utf8;
)或UTF-8(use utf8;
)编码。
°
不在ASCII字符集中,而且您显然也没有use utf8;
,因此您的程序可能无法如您所愿地包含°
。
首先,使用UTF-8(如果尚未编码)对程序进行编码,然后通过添加
告诉Perl您的程序已使用UTF-8编码
use utf8; # The source code is encoded using UTF-8.
第二,您显然也没有告诉Perl对您打印的内容进行编码。通过添加
来解决此问题use open ':std', ':encoding(UTF-8)'; # The terminal provides/expects UTF-8.
后者为在编译指示范围内打开的文件设置默认编码。如果要避免这种情况,可以改用以下内容:
BEGIN { # The terminal provides/expects UTF-8.
binmode(STDIN, ':encoding(UTF-8)');
binmode(STDOUT, ':encoding(UTF-8)');
binmode(STDERR, ':encoding(UTF-8)');
}