为什么 $_ =~ “正则表达式”在 Perl 中有效?

问题描述 投票:0回答:3

我知道在 Perl 中,最常见的有效正则表达式是这样的:

$_ =~ m/regular expression/;

# and "m" can be omit
$_ =~ /regular expression/;

我可以使用

qr
创建正则表达式引用,如下所示:

my $regex = qr/regular expression/;
$_ =~ m/$regex/;

# and "m//" can be omit:
$_ =~ $regex;

但我尝试过这个:

my $str = "regular expression";
$_ =~ $str; # why this is valid?

它没有给我任何错误信息并且工作正常。不知道为什么,我觉得应该是这样的:

my $str = "regular expression";
$_ =~ m/$str/;

# or
my $str = "regular expression";
my $regex = qr/$str/;
$_ =~ $regex;

谁能解释为什么

$_ =~ $str
在 Perl 中有效?

perl
3个回答
8
投票

它在 perlre “基础知识”下说

尚未存储在某些变量中的模式必须在两端用分隔符分隔。

(以及 delimite(d/r) 中不正确的 double-t )并且比这似乎允许的自由更多一点,因为字符串中的模式也不需要分隔符。见下文。

因此,变量中的模式不需要分隔符。运算符

=~
在perlop中的

“绑定运算符”中讨论过

将标量表达式绑定到模式匹配。

并且(我强调)

如果正确的参数是表达式而不是搜索模式、替换或音译,则它会 在运行时被解释为搜索模式。

运算符不关心其右侧的分隔符,并且可以在运行时从表达式形成“正则表达式模式”。

perlop 中的“解析引用结构的血腥细节”部分除了本身具有启发性之外也对此有所帮助。在识别出引用的结构并插入所包含的文本后,就进入了“解析正则表达式”

经过上述预处理后...生成的string被传递到RE引擎进行编译。

(我的重点)

这是对 Perl 如何处理引用结构和 一旦字符串由带引号的结构构成,就不需要(额外的)分隔符。

m/RE/
(等)在前面的“插值”项目符号中讨论过,它显示了一些不能与纯字符串一起用于模式的东西,但这显然不是强制性的。

一个例子

"hello" =~ ( '(' . join('|', qw(a b l)) . ')' );  # $1 has "l"

RHS 上的外括号仅用于优先级,以隔离产生模式的表达式。也可以使用

do
块:
$s =~ do { ... };

不过我建议不要这么做;如您所料,使用

qr
。一方面,使用字符串(而不是使用
qr
构建的正则表达式)是有限制的。而且,它更容易出现愚蠢的错误。


请注意,虽然对于许多模式,可以使用

qr
""
(或其运算符形式
qq()
)来准备模式(或将以这种方式解释的字符串)——但它们并不相同。它们的引用规则非常相似,但是
qr
准备了一个 正则表达式,如 Regexp Quote-Like Operators

中所示

...与包含相同字符的字符串神奇地不同...

首先,请记住,通过

qr
,您可以使用修饰符。


3
投票

Perl 努力成为一种自然语言,因此,这些习惯形式

''
""
,根据上下文可能有不同的通用形式。这是直接取自Programming Perl,第 4 版(第 71 页),表 2-7 的表格。报价结构:

+-----------+---------+-----------------------+--------------+
| Customary | Generic | Meaning               | Interpolates |
+-----------+---------+-----------------------+--------------+
| ''        | q//     | Literal string        | No           |
+-----------+---------+-----------------------+--------------+
| ""        | qq//    | Literal string        | Yes          |
+-----------+---------+-----------------------+--------------+
| ``        | qx//    | Command execution     | Yes          |
+-----------+---------+-----------------------+--------------+
| ()        | qw//    | Word list             | No           |
+-----------+---------+-----------------------+--------------+
| //        | m//     | Pattern match         | Yes          |
+-----------+---------+-----------------------+--------------+
| s///      | s///    | Pattern substitution  | Yes          |
+-----------+---------+-----------------------+--------------+
| tr///     | y///    | Character translation | No           |
+-----------+---------+-----------------------+--------------+
| ""        | qr//    | Regular expression    | Yes          |
+-----------+---------+-----------------------+--------------+

示例:

在此示例中,字符串被转换为模式。不过,这里必须小心,因为当您从双引号字符串构造模式时,必须转义斜杠。

在这里你可以清楚地看到:

my $pat = "hello\\s+world"; #double-slash to escape the slash

if ("hello       world" =~ $pat) {
    print "hello, world\n";
}

输出:

hello, world

2
投票

这由

perlop
=~ 的文档回答:

如果正确的参数是表达式而不是搜索模式、替换或音译,则在运行时将其解释为搜索模式。


只有少数几件事可以合法遵循

=~
:

  • 匹配运算符 (
    m//
    )
  • 替换运算符 (
    s///
    )
  • 音译运算符 (
    tr///
    )

现在,如果在 =~ 的右侧发现任何其他内容,Perl

可以
给出语法错误,如您所料。但它却做了一些更有用的事情。如果它找到除上述运算符之外的其他运算符,则表达式的结果将用作隐式匹配运算符的模式。

这方便地允许

$s =~ get_pattern()               # do { my $pat = get_pattern(); $s =~ /$pat/ }

$s =~ ( $sub_pat1 . $sub_pat2 )   # do { my $pat = $sub_pat1 . $sub_pat2; $s =~ /$pat/ }
© www.soinside.com 2019 - 2024. All rights reserved.