14

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

foo
quux
bar

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

foo
baz
quux

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

if( grep {$_ =~ m/^$word$/i} @arr)

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

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

问题:

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

4

5 回答 5

34

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

if( grep {$_ =~ m/^\Q$word\E$/i} @arr)
于 2010-01-04T18:25:12.227 回答
18

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 告诉它在哪里停止(有关详细信息,请参阅 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 $@;
    }
于 2010-01-04T18:30:53.430 回答
13

正确答案是 - 不要使用正则表达式。我并不是说正则表达式不好,但是将它们用于(等于)简单的相等性检查是矫枉过正的。

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

于 2010-01-04T18:30:03.077 回答
5

报价元

返回带有反斜杠的所有非“单词”字符的 EXPR 的值。

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

于 2010-01-04T18:21:35.230 回答
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";
      }
于 2010-01-04T18:36:02.563 回答