Perl 正则表达式匹配大型 Unicode 代码点

Posted

技术标签:

【中文标题】Perl 正则表达式匹配大型 Unicode 代码点【英文标题】:Perl regular expression matching on large Unicode code points 【发布时间】:2012-09-22 17:52:00 【问题描述】:

我正在尝试用单引号或双引号替换各种字符。

这是我的测试文件:

# Replace all with double quotes
" fullwidth
“ left
” right
„ low
" normal

# Replace all with single quotes
' normal
‘ left
’ right
‚ low
‛ reverse
` backtick

我正在尝试这样做......

perl -Mutf8 -pi -e "s/[\x2018\x201A\x201B\xFF07\x2019\x60]/'/ug" test.txt
perl -Mutf8 -pi -e 's/[\xFF02\x201C\x201D\x201E]/"/ug' text.txt

但只有反引号字符被正确替换。我认为这与其他代码点太大有关,但我找不到任何关于此的文档。

这里我有一个one-liner,它转储了 Unicode 代码点,以验证它们是否与我的正则表达式匹配。

$ awk -F\  'print $1' test.txt | \
    perl -C7 -ne 'for(split(//))print sprintf("U+%04X", ord)." ".$_."\n"'

U+FF02 "
U+201C “
U+201D ”
U+201E „
U+0022 "

U+0027 '
U+2018 ‘
U+2019 ’
U+201A ‚
U+201B ‛
U+0060 `

为什么我的正则表达式不匹配?

【问题讨论】:

【参考方案1】:

它不匹配,因为您在调用 Perl 时忘记了 -CSAD,并且在您的环境中没有设置 $PERL_UNICODE。您只是说-Mutf8 来宣布您的源代码采用该编码。这不会影响您的 I/O。

你需要:

$ perl -CSAD -pi.orig -e "s/[\x2018\x201A\x201B\xFF07\x2019\x60]/'/g" test.txt

我确实在this answer 中多次提到过这种事情。

【讨论】:

@tchrist,请通过将 -CSAD 替换为 -CSD 来更正您的答案。我没有这样做的编辑权力。 @HansDeragon 完成。【参考方案2】:

使用use utf8;,您告诉 Perl 您的源代码是 UTF-8。这是无用的(尽管无害),因为您已将源代码限制为 ASCII。

使用/u,您告诉Perl 使用\s\d\w 的Unicode 定义。这是无用的(尽管无害),因为您不使用任何这些模式。

您没有解码您的输入,因此您的输入仅由字节组成,因此您班级中的大多数字符(例如\x2018)不可能匹配任何内容。你需要解码你的输入(当然,编码你的输出)。使用-CSD 可能会做到这一点。

perl -CSD -i -pe'
   s/[\x2018\x201A\x201B\xFF07\x2019\x60]/\x27/g;
   s/[\xFF02\x201C\x201D\x201E]/"/g;
' text.txt

【讨论】:

我讨厌必须弄清楚如何在 shell 中引用东西。我通常只选择\x27 技巧。 我刚做了''\'' 不假思索,买是的,'\x27 是个好主意。 我认为你的意思是“需要解码你的输入”,然后可能还“需要编码你的输出”。 @tchirst,错字已修复。已添加。

以上是关于Perl 正则表达式匹配大型 Unicode 代码点的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Perl 中仅匹配 Unicode 字符串中的完全组合字符?

PERL正则表达式笔记——概述

Perl模式匹配大型连载1--初识正则

如何在 perl 正则表达式替换命令中使用 unicode 字符?

Qt官方示例-正则测试工具

如何在 perl 正则表达式中组合多个 Unicode 属性?