假设您的终端使用 UTF-8 编码,
$ echo -n "é" | perl -ne 'printf "%vX\n", $_'
给予
C3.A9
所以 Perl 程序的输入没有在内部转换为 Unicode(它仍然是一个 UTF-8 字节的字符串)
要将输入转换为 Perl 字符串,请使用选项 -CI 在标准输入流上添加一个 UTF-8 层:
$ echo -n "é" | perl -CI -ne 'printf "%vX\n", $_'
现在是输出
E9
但是,如果您还尝试将字符打印回标准输出
你不会从终端得到é,而是一个unicode替换字符�。这是因为字符0xE9是Unicode,但终端期望UTF-8,而0xE9不是有效的UTF-8:
$ echo -n "é" | perl -CI -nE 'printf "$_: %vX\n", $_, $_'
�: E9
要获得正确的输出,您还可以在标准输出流上添加 UFT-8 编码层(使用 -CO 标志):
$ echo -n "é" | perl -CIO -nE 'printf "$_: %vX\n", $_, $_'
é: E9
根据perlunicode
"Upper" 是 "Uppercase" 的同义词,我们可以这样写
\p{Uppercase} 等价于 \p{Upper}
和
例如,\p{Uppercase} 匹配任何带有
Unicode“大写”属性
似乎如果您尝试在字节字符串上使用\p{Upper},您将不会收到来自 Perl 的任何警告。 0xC0 到 0xDE 范围内的字节也将匹配大写属性。试试
perl -E 'for $i (0x80..0xFF) {$_=chr $i; printf "%x\n", $i if /\p{Upper}/}'
这解释了你得到的输出:
$ echo "Whatéver 5" | perl -ape "s/(\p{Upper})/(\1)/g"
(W)hat(�)�ver 5
这里,字母 é 表示为 2 个字节(在 UTF-8 中)0xC3 和 0xA9,0xC3 将匹配 Unicode Upper 属性。
因此,解决您的问题的方法是在标准输入和输出上添加 UTF-8 编码层(您可以使用 -CS 组合 -CI 和 -CO):
echo "Whatéver 5" | perl -CS -ape "s/(\p{Upper})/(\1)/g"
有输出:
(W)hatéver 5