我想将文档中的 curl 单引号和双引号音译为中性引号。我认为它应该像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///的上述行为?
2条答案
按热度按时间rkttyhzu1#
您需要以下内容:
如果没有
use utf8;
,Perl期望源代码使用ASCII编码。所以你的第一个代码片段不可能包含“
,”
和’
。由于字符串文字是“8位干净”的,你的第一个代码片段相当于这显然是不正确的。要解决这个问题,请像在上一个代码片段中那样添加
use utf8;
。那么为什么最后一个片段不起作用呢?那是因为它实际上
这显然也是不正确的。您正在搜索编码的文本(UTF-8字节的字符串)以获得解码的文本(Unicode Code Points的字符串)。您需要解码您的输入,并编码您的输出。然后可以使用
use open ":std", ":encoding(UTF-8)";
实现,但-CS
可以在这里使用。最后是
从上面我们知道它相当于以下内容:
除非使用
/d
,否则如果右侧的字符数少于左侧,tr///
将重复最后一个字符。这就解释了
"""
的输出。enyaitl32#
为了解释你的不太复杂的例子
“
的UTF-8是序列e2 80 9c
。因为所有内容都被视为ASCII字符(字节),所以您的翻译命令会将这些字符替换为"
。这就是为什么您会得到三个双引号。在第一个例子中也发生了类似的事情。但是因为搜索字符串有9个ASCII字符,而替换有3个,所以只考虑Map的替换。所有字符的前两个UTF-8字节(
“”’
)是相同的,所以当被视为ASCII时,它们Map到替换字符串中的前两个字符。“
的第三个字节Map到替换字符串中的第三个字符。但是其他两个的第三个字节没有Map,而是被替换字符串的最后一个字符替换。如果在替换字符串中添加第四个字符,您可以更清楚地看到这一点。例如,如果输入是“”’
,则tr/“”’/""\047z/
将输出""'""z""z
。你的代码没有错,如果你把脚本写进一个文件,并正确使用
utf8
和binmode
,它会像预期的那样工作:输出:
""'
因此,您需要从命令行告诉Perl将
STDIN
视为UTF-8。您可以使用-C1
或更常见的选项-CS
来执行此操作,该选项将STDIN
,STDOUT
和STDERR
视为UTF-8。