当我在Perl的匹配运算符中插入变量时,如何转义元字符?

Pau*_*han 12 regex variables perl interpolation

假设我有一个包含我想要匹配的行的文件:

foo
quux
bar
Run Code Online (Sandbox Code Playgroud)

在我的代码中,我有另一个数组:

foo
baz
quux
Run Code Online (Sandbox Code Playgroud)

假设我们遍历文件,调用每个元素$word,以及我们正在检查的内部列表,@arr.

if( grep {$_ =~ m/^$word$/i} @arr)
Run Code Online (Sandbox Code Playgroud)

这样可以正常工作,但在某种可能的情况下,我们fo.在文件中有一个测试用例,它.在正则表达式中作为通配符操作符运行,fo.然后匹配foo,这是不可接受的.

这当然是因为Perl正在将变量插入到正则表达式中.

问题:

如何强制Perl按字面意思使用变量?

Iva*_*uev 33

用于\Q...\E在变量值插值后直接在perl字符串中转义特殊符号:

if( grep {$_ =~ m/^\Q$word\E$/i} @arr)
Run Code Online (Sandbox Code Playgroud)


bri*_*foy 17

perlfaq6的答案我如何匹配变量中的正则表达式?:


我们不必将模式硬编码到匹配运算符(或其他任何与正则表达式一起使用的代码)中.我们可以将模式放在变量中供以后使用.

匹配运算符是双引号上下文,因此您可以像双引号字符串一样插入变量.在这种情况下,您将正则表达式作为用户输入读取并将其存储在$ regex中.在$ regex中使用该模式后,可以在匹配运算符中使用该变量.

chomp( my $regex = <STDIN> );

if( $string =~ m/$regex/ ) { ... }
Run Code Online (Sandbox Code Playgroud)

$ regex中的任何正则表达式特殊字符仍然是特殊的,并且该模式仍然必须有效或Perl会抱怨.例如,在这种模式中有一个不成对的括号.

my $regex = "Unmatched ( paren";

"Two parens to bind them all" =~ m/$regex/;
Run Code Online (Sandbox Code Playgroud)

当Perl编译正则表达式时,它将括号视为内存匹配的开始.当它没有找到右括号时,它会抱怨:

Unmatched ( in regex; marked by <-- HERE in m/Unmatched ( <-- HERE  paren/ at script line 3.
Run Code Online (Sandbox Code Playgroud)

根据我们的情况,您可以通过多种方式解决这个问题.首先,如果您不希望字符串中的任何字符都是特殊字符,则可以在使用字符串之前使用quotemeta对其进行转义.

chomp( my $regex = <STDIN> );
$regex = quotemeta( $regex );

if( $string =~ m/$regex/ ) { ... }
Run Code Online (Sandbox Code Playgroud)

您也可以使用\ Q和\ E序列在匹配运算符中直接执行此操作.\ Q告诉Perl从哪里开始转义特殊字符,\ E告诉它在哪里停止(有关详细信息,请参阅perlop).

chomp( my $regex = <STDIN> );

if( $string =~ m/\Q$regex\E/ ) { ... }
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用qr //,正则表达式引用运算符(有关详细信息,请参阅perlop).它引用并可能编译模式,您可以将正则表达式标志应用于模式.

chomp( my $input = <STDIN> );

my $regex = qr/$input/is;

$string =~ m/$regex/  # same as m/$input/is;
Run Code Online (Sandbox Code Playgroud)

您可能还希望通过在整个事物周围包装一个eval块来捕获任何错误.

chomp( my $input = <STDIN> );

eval {
    if( $string =~ m/\Q$input\E/ ) { ... }
    };
warn $@ if $@;
Run Code Online (Sandbox Code Playgroud)

要么...

my $regex = eval { qr/$input/is };
if( defined $regex ) {
    $string =~ m/$regex/;
    }
else {
    warn $@;
    }
Run Code Online (Sandbox Code Playgroud)


小智 12

正确答案是 - 不要使用正则表达式.我不是说正则表达式是坏的,但是使用它们(等于)简单的相等检查是过度的.

使用:grep { lc($_) eq lc($word) } @arr并且快乐.

  • 好点子.正则表达式解决方案是旧的和更复杂的代码的残余. (2认同)

Pau*_*han 5

Quotemeta

返回EXPR的值,并将所有非"单词"字符反斜杠.

http://perldoc.perl.org/functions/quotemeta.html