2012-10-01 47 views
4

我试图用单引号或双引号替换各种字符。大型Unicode代码点上的Perl正则表达式匹配

这里是我的测试文件:

# 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/[\x{2018}\x{201A}\x{201B}\x{FF07}\x{2019}\x{60}]/'/ug" test.txt 
perl -Mutf8 -pi -e 's/[\x{FF02}\x{201C}\x{201D}\x{201E}]/"/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 ` 

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

回答

16

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

您需要:

$ perl -CSAD -pi.orig -e "s/[\x{2018}\x{201A}\x{201B}\x{FF07}\x{2019}\x{60}]/'/g" test.txt 

我确实提到这样的事情在this answer几次。

+0

非常感谢。 –

+0

@tchrist,请通过将-CSAD替换为-CSD来更正您的答案。我没有编辑权力这样做。 –

+0

@HansDeragon完成。 – tchrist

6

随着use utf8;,你告诉Perl你的源代码是UTF-8。这是无用的(虽然无害),因为你已经限制你的源代码到ASCII。

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

您没有对输入进行解码,所以您的输入仅包含字节,因此您班级中的大多数字符(例如\x{2018})都不可能与任何内容匹配。你需要解码你的输入(当然,编码你的输出)。使用-CSD可能会这样做。

perl -CSD -i -pe' 
    s/[\x{2018}\x{201A}\x{201B}\x{FF07}\x{2019}\x{60}]/\x27/g; 
    s/[\x{FF02}\x{201C}\x{201D}\x{201E}]/"/g; 
' text.txt 
+0

我讨厌弄清楚如何在shell中引用东西。我通常只是选择'\ x27'技巧。 – tchrist

+0

我只是做'''⇒''''''没有想到,买呀,''''''\ x27'是个好主意。 – ikegami

+0

我认为你的意思是“需要解码你**输入**”,并且可能还需要“编码你的输出”。 – tchrist