要在Perl中处理命令行上的UTF-8,我们必须考虑STDIN、STDOUT、STDERR、参数以及源代码(作为
-e
或
-E
选项的参数给出)。
考虑以下测试用例:
echo -n "одобрение за" | perl -Mstrict -w -E '
while (<STDIN>){ s/\X\K/ /g; say; }
say "Arguments and their length:";
say " $_\t", length("$_") foreach @ARGV;
say "Length of in the source code is ", length("");
' a
这是一个很好的测试用例,因为它有3个地方包含UTF-8编码字符:
- 在标准输入上,
- 作为参数,以及
- 在源代码中(作为传递给
-E
选项的参数)。
(顺便说一下,我的终端处于UTF-8区域设置。)
结果:
� � � � � � � � � � � � � � � � � � � � � �
Arguments and their length:
a 1
4
Length of in the source code is 4
首先,让我们摆脱问号。告诉 Perl 标准流是 UTF-8 编码的字符。为此,请添加 -CSD
:
echo -n "одобрение за" | perl -Mstrict -w -CSD -E '
while (<STDIN>){ s/\X\K/ /g; say; }
say "Arguments and their length:";
say " $_\t", length("$_") foreach @ARGV;
say "Length of in the source code is ", length("");
' a
注意:我本可以简单地使用
-C
,因为
-C
意味着
-CSDL
,在UTF-8语言环境下,这与
-CSD
相同,如
perlrun所解释的那样。
о д о б р е н и е з а
Arguments and their length:
a 1
ð 4
Length of ð in the source code is 4
很好,这样就解决了问号的问题。
但现在参数和源代码中的表情符号已经混乱了。
我们必须告诉Perl我们的参数是UTF-8编码。我们可以通过将-CSD
更改为-CSDA
来实现:
echo -n "одобрение за" | perl -Mstrict -w -CSDA -E '
while (<STDIN>){ s/\X\K/ /g; say; }
say "Arguments and their length:";
say " $_\t", length("$_") foreach @ARGV;
say "Length of in the source code is ", length("");
' a
结果:
о д о б р е н и е з а
Arguments and their length:
a 1
1
Length of ð in the source code is 4
很好。表情符号参数已经被修复,其长度为1个字符,如预期所述。
源代码中的表情符号仍然存在问题。
要告知perl源代码已编码为UTF-8,请将use utf8;
添加到源代码或-Mutf8
添加到命令行选项中:
echo -n "одобрение за" | perl -Mutf8 -Mstrict -w -CSDA -E '
while (<STDIN>){ s/\X\K/ /g; say; }
say "Arguments and their length:";
say " $_\t", length("$_") foreach @ARGV;
say "Length of in the source code is ", length("");
' a
结果:
о д о б р е н и е з а
Arguments and their length:
a 1
1
Length of in the source code is 1
好的,现在我们得到了源代码中表情符号字符的预期结果。
总结:
- 添加
-CSD
以告诉perl标准流是UTF-8编码的。
- 将其更改为
-CSDA
以处理UTF-8编码的参数。
- 在源代码中添加
use utf8;
或添加-Mutf8
选项以告诉perl源代码是UTF-8编码的。
$ sed 's/./& /g' <<< "одобрение за"
结果为:о д о б р е н и е з а
- Ignacio Vazquez-Abramssed 's/./& /g'
对于字形不起作用(如果文本包含组合字符,例如"Солжени́цын"
,则很重要)。在Perl、Python中,可以使用/\X/
正则表达式来解决这个问题。 - jfs