Perl,动态生成的正则表达式字符串,带有反斜杠元字符的奇怪行为

时间:2013-05-28 15:13:05

标签: regex perl

这是一个小的perl片段:

my $n = 1;
my $re_str = '\d';
my $re_str_q = '\Q1\E';

printf "re_str   match: %s\n", ($n =~ /$re_str/);
printf "re_str_q match: %s\n", ($n =~ /$re_str_q/);
printf "direct match: %s\n", ($n =~ /\Q1\E/);

运行时产生以下输出:

re_str   match: 1
re_str_q match: 
direct match: 1

所以,我的问题是为什么第二个printf不匹配?

5 个答案:

答案 0 :(得分:9)

如果你改变了

my $re_str_q = '\Q1\E'; #from 
my $re_str_q = qr/\Q1\E/; #to

这是传递动态生成的正则表达式的正确方法,然后它会给出以下结果

re_str   match: 1
re_str_q match: 1
direct match: 1

此外,如果您使用过

use strict;
use warnings;

你会收到警告

Unrecognized escape \Q passed through in regex; marked by <-- HERE in m/\Q <-- HERE 1\E/ at so.pl line 9.
Unrecognized escape \E passed through in regex; marked by <-- HERE in m/\Q1\E <-- HERE / at so.pl line 9.

哪会给你一些关于出了什么问题的迹象。

<强>更新

为了更详细地了解这一点,您可以阅读 here

摘录参考文件

以下转义序列在 interpolate 的构造中可用,但在 transliterations 中不可用。

\l  lowercase next character only
\u  titlecase (not uppercase!) next character only
\L  lowercase all characters till \E or end of string
\U  uppercase all characters till \E or end of string
\F  foldcase all characters till \E or end of string
\Q quote (disable) pattern metacharacters till \E or
end of string
\E  end either case modification or quoted section
(whichever was last seen)

请参阅quotemeta,了解\ Q。

引用的字符的确切定义

\ L,\ U,\ F和\ Q可以叠加,在这种情况下,每个都需要一个\ E.例如:

say"This \Qquoting \ubusiness \Uhere isn't quite\E done yet,\E is it?";
This quoting\ Business\ HERE\ ISN\'T\ QUITE\ done\ yet\, is it?

答案 1 :(得分:3)

您正在使用单引号来构建“动态生成的正则表达式”。使用use warnings perl会告诉您:

  

无法识别的转义\ Q在正则表达式中传递;标记为&lt; - HERE in m / \ Q&lt; - HERE 1 \ E / at ...

perldoc perlop会告诉您:

  

单引号

     

单引号表示文本将按字面处理,不进行插值    内容。这类似于单引号字符串,除了反斜杠没有特殊之处    意思是,“\\”被视为两个反斜杠,而不是像其他人一样    引用构造。

     

这是perl中唯一的引用形式,无需担心转义    内容,代码生成器可以并且确实可以充分利用它。

答案 2 :(得分:3)

\ Q不是正则表达式转义符,它是一个字符串转义符,在字符串中被替换,因此“\ Q1 \ E”将等同于quotemeta('1')。

所以你需要使用可以插入这些序列的引用,比如“”或qr //,或者调用quotemeta而不是尝试使用字符串转义。

答案 3 :(得分:2)

\ Q和\ E都由字符串插值处理,而不是正则表达式引擎。您绕过第一个和第二个printf行中的字符串插值。搜索 Programming Perl 以获取“七个转换转义”以进行讨论。它们是:\N{...} \U \u \L \l \E \Q \F。 (不要问我为什么有八个。)

答案 4 :(得分:2)

正则表达式涉及两种转义。

  • 解析文字时处理的转义。
  • 正则表达式引擎处理的转义。

例如,

  • \Q..\E是前者。
  • \d是后者。
  • \n同样善良。

这意味着

  • "abc\Q!@#\Edef"生成12个字符串abc\!\@\#def
  • qq/abc\Q!@#\Edef/完全相同。
  • qr/abc\Q!@#\Edef/生成12个字符串abc\!\@\#def,然后将其编译为与9个字符abc!@#def匹配的正则表达式模式。

但是单引号不处理这样的转义,所以

  • 'abc\Q!@#\Edef'生成13个字符串abc\Q!@#\Edef

正则表达式引擎无法理解\Q\E,因此如果您最后将最后一个字符串传递给它,它会发出警告,然后它会尝试匹配11个字符{ {1}}。

修复方法是改变

abcQ!@#Edef

my $re_str   = '\d';         # Produces string \d
my $re_str_q = '\Q1\E\';     # Produces string \Q1\E

或更好,

my $re_str   = "\\d";        # Produces string \d
my $re_str_q = "\Q1\E";      # Produces string \1

Read了解更多关于my $re_str = qr/\d/; # Produces regex \d my $re_str_q = qr/\Q1\E/; # Produces regex \1 的内容。