当我在 Perl 的匹配运算符中插入变量时,如何转义元字符?
-
18-09-2019 - |
题
假设我有一个文件,其中包含我要匹配的行:
foo
quux
bar
在我的代码中,我有另一个数组:
foo
baz
quux
假设我们遍历文件,调用每个元素 $word
, ,以及我们正在检查的内部列表, @arr
.
if( grep {$_ =~ m/^$word$/i} @arr)
这工作正常,但在某种可能的情况下,我们有一个测试用例 fo.
在该文件中, .
在正则表达式中充当通配符运算符,并且 fo.
然后匹配 foo
, ,这是不可接受的。
这当然是因为 Perl 正在将变量插入到正则表达式中。
问题:
如何强制 Perl 按字面意思使用变量?
解决方案
正确的答案是 - 不使用正则表达式。我并不是说正则表达式是坏的,但使用它们(什么等于)简单的平等检查是矫枉过正。
使用:grep { lc($_) eq lc($word) } @arr
和快乐
其他提示
使用\Q...\E
在Perl串直接逸出特殊符号变量值插值之后:
if( grep {$_ =~ m/^\Q$word\E$/i} @arr)
从 perlfaq6的回答 如何匹配变量中的正则表达式?:
我们不必将模式硬编码到匹配运算符(或任何与正则表达式一起使用的其他内容)中。我们可以将模式放入变量中以供以后使用。
匹配运算符是双引号上下文,因此您可以像双引号字符串一样插入变量。在本例中,您读取正则表达式作为用户输入并将其存储在 $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 告诉 Perl 在哪里停止(更多细节请参见 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 $@;
}
我不认为你想在这种情况下,一个正则表达式,因为你是不匹配的模式。你要找的,你已经知道字符的文字序列。建立与所述值的散列相匹配,并使用该过滤@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";
}