是使用“||”在禁止子字符串搜索?

Is the use of "||" in a substring search prohibited?

我有一个小的 Perl 脚本,其中包含如下子字符串搜索。

#!/usr/bin/perl
use strict;
use warnings;

my $line = "this && is || a test if && ||";

my $nb_if = findSymbols($line, "if ");
my $nb_and = findSymbols($line, "&&");
my $nb_or = findSymbols($line, "||");

print "\nThe result for this func is $nb_if=if , $nb_and=and, $nb_or=or\n";

sub findSymbols {
    my $n = () = ($_[0] =~ m/$_[1]/g);
    return $n;
}

应该return:

The result for this func is 1=if , 2=and, 2=or

但是,它 returns:

The result for this func is 1=if , 2=and, 30=or

我不明白我的代码有什么问题。

|m//使用的正则表达式中的交替运算符。您需要使用反斜杠转义每个 | 以匹配文字 |s.

my $nb_or = findSymbols($line, "\|\|");  # or '\|\|`

(但使用 quotemeta 作为 是一个更好的主意,因为它使您的调用者不必担心应该属于 findSymbols 提供的抽象的一部分的细节.)

使用 quotemeta 转义包含 || 的正则表达式(以及您传递给函数的任何其他字符)的特殊含义:

sub findSymbols {
    my $pat = quotemeta $_[1];
    my $n = () = ($_[0] =~ m/$pat/g);
    return $n;
}

竖线符(|)在正则表达式中有特殊含义。它的意思是“或”(匹配左边的事物或右边的事物)。因此,有一个仅由两个管道组成的正则表达式被解释为“匹配一个空字符串或一个空字符串或一个空字符串”——并且匹配字符串中的任何地方(30 次!)

所以你需要停止将管道解释为特殊字符,让它只代表一个实际的管道字符。以下是三种方法:

  1. 在创建传递给 findSymbols().

    的字符串时,使用反斜杠转义管道
    # Note: I've also changed "..." to '...'
    # to avoid having to double-escape
    my $nb_or = findSymbols($line, '\|\|');
    
  2. 使用 quotemeta() 自动转义传递给 findSymbols().

    的任何字符串中的有问题的字符
    my $escaped_regex = quotemeta($_[0]);
    my $n = () = ($_[0] =~ m/$escaped_regex/g);
    
  3. 使用 \Q...\E 自动转义正则表达式中使用的任何有问题的字符。

    # Note: In this case, the \E isn't actually needed
    # as it's at the end of the regex.
    my $n = () = ($_[0] =~ m/\Q$_[0]\E/g);
    

有关在 Perl 中使用正则表达式的更多详细信息,请参阅 perlretut and perlre