假设我有一个包含我想要匹配的行的文件:
foo
quux
bar
在我的代码中,我有另一个数组:
foo
baz
quux
假设我们遍历文件,调用每个元素$word
,以及我们正在检查的内部列表@arr
。
if( grep {$_ =~ m/^$word$/i} @arr)
这是正常的,但在某种情况下,我们在文件中有fo.
的测试用例,.
在正则表达式中作为通配符运算符运行,fo.
然后匹配foo
,这是不可接受的。
这当然是因为Perl正在将变量插入到正则表达式中。
问题:
如何强制Perl按字面意思使用变量?
答案 0 :(得分:33)
使用\Q...\E
在变量值插值后直接在perl字符串中转义特殊符号:
if( grep {$_ =~ m/^\Q$word\E$/i} @arr)
答案 1 :(得分:17)
从perlfaq6回答How do I match a regular expression that's in a variable?:
我们不必将模式硬编码到匹配运算符(或其他任何与正则表达式一起使用的代码)中。我们可以将模式放在变量中供以后使用。
匹配运算符是双引号上下文,因此您可以像双引号字符串一样插入变量。在这种情况下,您将正则表达式作为用户输入读取并将其存储在$ regex中。在$ regex中使用该模式后,可以在匹配运算符中使用该变量。
chomp( my $regex = <STDIN> );
if( $string =~ m/$regex/ ) { ... }
$ regex中的任何正则表达式特殊字符仍然是特殊的,并且该模式仍然必须有效或Perl会抱怨。例如,在这种模式中有一个不成对的括号。
my $regex = "Unmatched ( paren";
"Two parens to bind them all" =~ m/$regex/;
当Perl编译正则表达式时,它将括号视为内存匹配的开始。当它没有找到右括号时,它会抱怨:
Unmatched ( in regex; marked by <-- HERE in m/Unmatched ( <-- HERE paren/ at script line 3.
根据我们的情况,您可以通过多种方式解决这个问题。首先,如果您不希望字符串中的任何字符都是特殊字符,则可以在使用字符串之前使用quotemeta对它们进行转义。
chomp( my $regex = <STDIN> );
$regex = quotemeta( $regex );
if( $string =~ m/$regex/ ) { ... }
您也可以使用\ Q和\ E序列在匹配运算符中直接执行此操作。 \ Q告诉Perl从哪里开始转义特殊字符,\ E告诉它在哪里停止(有关详细信息,请参阅perlop)。
chomp( my $regex = <STDIN> );
if( $string =~ m/\Q$regex\E/ ) { ... }
或者,您可以使用qr //,正则表达式引用运算符(有关详细信息,请参阅perlop)。它引用并可能编译模式,您可以将正则表达式标志应用于模式。
chomp( my $input = <STDIN> );
my $regex = qr/$input/is;
$string =~ m/$regex/ # same as m/$input/is;
您可能还希望通过在整个事物周围包装一个eval块来捕获任何错误。
chomp( my $input = <STDIN> );
eval {
if( $string =~ m/\Q$input\E/ ) { ... }
};
warn $@ if $@;
或者...
my $regex = eval { qr/$input/is };
if( defined $regex ) {
$string =~ m/$regex/;
}
else {
warn $@;
}
答案 2 :(得分:12)
正确的答案是 - 不要使用正则表达式。我不是说正则表达式很糟糕,但是使用它们(等于)简单的相等检查是过度的。
使用:grep { lc($_) eq lc($word) } @arr
并且快乐。
答案 3 :(得分:5)
答案 4 :(得分:2)
在这种情况下,我认为你不想要一个正则表达式,因为你没有匹配一个模式。您正在寻找您已经知道的文字字符序列。使用要匹配的值构建哈希,并使用它来过滤@arr
:
open my $fh, '<', $filename or die "...";
my %hash = map { chomp; lc($_), 1 } <$fh>;
foreach my $item ( @arr )
{
next unless exists $hash{ lc($item) };
print "I matched [$item]\n";
}