提问人:Reece 提问时间:8/24/2023 最后编辑:zdimReece 更新时间:8/24/2023 访问量:77
为什么我不能在 perl tr/// 表达式中使用引号?
Why can't I use quotes in perl tr/// expressions?
问:
我想在文档中将卷曲的单引号和双引号音译为中性引号。我以为它应该像 一样简单,但这不起作用。例如:perl -pe 'tr/“”’/""\047/'
snafu$ echo '“' | perl -pe 'tr/“”’/""\047/'
""'
snafu$ echo '“”’' | perl -pe 'tr/“”’/""\047/'
""'""'""'
请注意,单个 “ 将成为右侧的完整字符集。在第二个示例中,它发生了三次。
而且,更出乎意料的是(对我来说)即使对于这个微不足道的情况,也会发生三重奏:
snafu$ echo '“' | perl -pe 'tr/“/"/'
"""
这种行为似乎与我在 ASCII 字符中看到的行为非常不同,如下所示:
snafu$ echo "Larry Wall" | perl -pe 'tr/ay/AY/'
LArrY WAll
我也尝试过调用,但这也没有达到我的预期:perl -Mutf8
# not triplicated, but also not transliterated
snafu$ echo '“' | perl -Mutf8 -pe 'tr/“”’/""\047/'
“
是什么解释了 tr/// 的上述行为?
答:
您需要满足以下条件:
perl -CS -Mutf8 -pe 'tr/“”’/""\047/'
如果没有 ,Perl 期望源代码使用 ASCII 进行编码。因此,您的第一个代码段不可能包含 和 。由于字符串文字是“8 位干净的”,因此您的第一个代码段等效于use utf8;
“
”
’
tr/\xE2\x80\x9C\xE2\x80\x9D\xE2\x80\x99/""'/
这显然是不正确的。要解决此问题,请像在上一个代码段中所做的那样添加。use utf8;
那么,为什么最后一个片段不起作用呢?那是因为它有效地做到了
"\xE2\x80\x9C" =~ tr/\x{201C}\x{201D}\x{2019}/""'/;
这显然也是不正确的。您正在编码文本(UTF-8 字节字符串)中搜索解码文本(Unicode 码位字符串)。您需要对输入进行解码,并对输出进行编码。然后可以使用 来实现,但可以在这里使用。use open ":std", ":encoding(UTF-8)";
-CS
最后,还有
echo '“' | perl -pe 'tr/“/"/'
综上所述,我们知道它相当于以下内容:
"\xE2\x80\x9C" =~ tr/\xE2\x80\x9C/"/;
除非使用 ,否则如果右边的字符比左边的字符少,则重复最后一个字符。这使得上述等同于/d
tr///
"\xE2\x80\x9C" =~ tr/\xE2\x80\x9C/"""/;
这解释了输出。"""
解释您不太复杂的示例
snafu$ echo '“' | perl -pe 'tr/“/"/'
"""
的 UTF-8 是序列 。由于所有内容都被视为 ASCII 字符(字节),因此您的翻译命令会将其中每个字符替换为 .这就是为什么你得到三个双引号的原因。“
e2 80 9c
"
在你的第一个例子中也发生了类似的事情。但是,由于搜索字符串有 9 个 ASCII 字符,而替换字符串有 3 个字符,因此仅考虑映射的替换。所有字符 () 的前两个 UTF-8 字节是相同的,因此当被视为 ASCII 时,它们会映射到替换字符串中的前两个字符。然后,第三个字节映射到替换字符串中的第三个字符。但是其他两个字节的第三个字节没有映射,并被替换字符串的最后一个字符替换。如果在替换字符串中添加第四个字符,则可以更清楚地看到这一点。例如,如果输入是 ,则输出。“”’
“
tr/“”’/""\047z/
""'""z""z
“”’
你的代码没有错。如果将脚本写入文件并正确使用 和 ,它将按预期工作:utf8
binmode
use utf8;
binmode STDIN, ":utf8";
my $s = <STDIN>;
$s =~ tr/“”’/""'/;
print "$s";
输出:
""'
因此,您需要从命令行告诉Perl将其视为UTF-8。您可以使用 或 更常见的选项 来做到这一点,该选项将把 、 和 视为 UTF-8。STDIN
-C1
-CS
STDIN
STDOUT
STDERR
`echo '“”’' | perl -Mutf8 -CS -pe 'tr/“”’/""\047/'
评论
:utf8
:encoding(UTF-8)
-CS
utf8
UTF-8
-CS
这是一个很好的电话,因为无论如何都不够。那可以做 STDIN,但你也需要做 STDOUT。这意味着您至少需要 aka。您可以使用 进行测试。-C1
-C3
-CIO
“é”
-C
-C0
-C1
评论