了解Perl正则表达式修饰符/ m和/ s

时间:2014-04-09 12:29:53

标签: regex perl

我一直在用修饰符s m和g读取perl正则表达式。我知道// g是一个全局匹配,它将是一个贪婪的搜索。

但我对修饰符s和m感到困惑。任何人都可以用代码示例解释s和m之间的区别,以显示它是如何不同的?我尝试过在线搜索,但它只在链接http://perldoc.perl.org/perlre.html#Modifiers中给出了解释。在stackoverflow中,我甚至看到人们一起使用s和m。 Isn&s; s是与m?相反的吗?

//s 
//m 
//g

我无法使用m。

匹配多行
use warnings;
use strict;
use 5.012;

my $file; 
{ 
 local $/ = undef; 
 $file = <DATA>; 
};
my @strings = $file =~ /".*"/mg; #returns all except the last string across multiple lines
#/"String"/mg; tried with this as well and returns nothing except String
say for @strings;

__DATA__
"This is string"
"1!=2"
"This is \"string\""
"string1"."string2"
"String"
"S
t
r
i
n
g"

4 个答案:

答案 0 :(得分:14)

您链接到自己的documentation对我来说非常清楚。如果你能解释你对理解它有什么问题,以及你如何认为/s/m是对立的,那将会有所帮助。

非常简单,/s会更改点元字符.的行为,以便它匹配任何字符。通常它会匹配换行符"\n"以外的任何内容,因此即使它包含换行符,也会将该字符串视为 s ingle行。

/m修改了插入符^和美元$元字符,以便它们匹配字符串中的换行符,将其视为 m < / strong> ulti-line string。通常它们只匹配字符串的开头和结尾。

你不应该对/g修饰符&#34;贪婪&#34;感到困惑。它适用于 g 最终匹配,它会在字符串中找到所有出现的模式。术语 greedy 通常是用户在模式中的量词的行为。例如,.*被认为是贪婪的,因为它会匹配尽可能多的字符,而不是.*?,它将尽可能匹配少数字符。


<强>更新

在修改后的问题中,您使用的是/".*"/mg,其中/m无关紧要,因为如上所述,该修饰符只会改变$和{{1}的行为元字符,你的模式中没有。

将其更改为^会稍微改善一点,因为/".*"/sg现在可以匹配每行末尾的换行符,因此模式可以匹配多行字符串。 (请注意,对象字符串在此处被视为&#34;单行&#34; - 即匹配的行为就像没有换行符一样它就.而言。)这里的Hower是 greedy 的常规含义,因为该模式现在匹配从第一行中的第一个双引号到最后一个双引号的所有内容 - 引用最后一行的末尾。我认为这不是你想要的。

有几种方法可以解决这个问题。我建议更改您的模式,以便您想要的字符串是双引号,后跟任何字符序列除了双引号,然后是另一个双引号。这是.写的(请注意,/"[^"]*"/g修饰符不再是必需的,因为模式中现在没有点)并且几乎可以做你想要的,除了转义的双引号被视为结束模式。

看看这个程序及其输出,注意我在每场比赛开始时都放了一个V形/s,以便区分它们

>>

<强>输出

use strict;
use warnings;

my $file = do {
  local $/;
  <DATA>; 
};

my @strings = $file =~ /"[^"]*"/g;

print ">> $_\n\n", for @strings;

__DATA__
"This is string"
"1!=2"
"This is \"string\""
"string1"."string2"
"String"
"S
t
r
i
n
g"

正如您所看到的,除了在>> "This is string" >> "1!=2" >> "This is \" >> "" >> "string1" >> "string2" >> "String" >> "S t r i n g" 中找到两个匹配项"This is \"string\"""This is \"之外,现在一切正常。修复可能比你想要的更复杂,但它完全可能。如果您需要修复,请说出来。


<强>更新

我也可以完成这个。要忽略转义的双引号并将它们视为字符串的一部分,我们需要接受 "" 除双引号之外的任何字符。这是使用正则表达式交替运算符\"完成的,必须在非捕获括号|内分组。最终结果是(?: ... )(反斜杠本身必须被转义,因此它被加倍),当放入上面的程序时,产生这个输出,我认为这是你想要的。

/"(?:\\"|[^"])*"/g

答案 1 :(得分:5)

/m/s都会影响匹配运算符处理多行字符串的方式。

使用/m修饰符,^$匹配字符串中任何行的开头和结尾。如果没有/m修饰符,^$只会匹配字符串的开头和结尾。

示例:

$_ = "foo\nbar\n";

/foo$/,  /^bar/       do not match
/foo$/m, /^bar/m      match

使用/s修饰符,特殊字符.匹配包括换行符在内的所有字符。如果没有/s修饰符,.会匹配除换行符之外的所有字符。

$_ = "cat\ndog\ngoldfish";

/cat.*fish/           does not match
/cat.*fish/s          matches

可以同时使用/sm修饰符。

$_ = "100\n101\n102\n103\n104\n105\n";

/^102.*104$/          does not match
/^102.*104$/s         does not match
/^102.*104$/m         does not match
/^102.*104$/sm        matches

答案 2 :(得分:4)

使用/".*"/mg您的匹配

  1. "
  2. 开头
  3. 然后.*"尽可能匹配每个字符(\n除外)"
  4. 由于您使用/g并且匹配在第二个"停止,因此正则表达式会尝试重复前两个步骤
  5. /m因为您未使用^$锚点而无法与众不同
  6. 由于您的示例中已经转义了引号,因此正则表达式不是执行所需操作的最佳工具。 如果情况并非如此,并且您想要两个引号之间的所有内容,那么/".*?"/gs就可以完成这项任务。

答案 3 :(得分:1)

Borodin的正则表达式适用于本实验作业中的示例。

然而,反斜杠也有可能逃脱。当一个包含字符串中的窗口路径时会出现这种情况,因此以下正则表达式会捕获这种情况:

use warnings;
use strict;
use 5.012;

my $file = do { local $/; <DATA>};

my @strings = $file =~ /"(?:(?>[^"\\]+)|\\.)*"/g;

say "<$_>" for @strings;

__DATA__
"This is string"
"1!=2"
"This is \"string\""
"string1"."string2"
"String"
"S
t
r
i
n
g"
"C:\\windows\\style\\path\\"
"another string"

输出:

<"This is string">
<"1!=2">
<"This is \"string\"">
<"string1">
<"string2">
<"String">
<"S
t
r
i
n
g">
<"C:\\windows\\style\\path\\">
<"another string">

快速解释模式:

my @strings = $file =~ m{
    "
        (?:
            (?>            # Independent subexpression (reduces backtracking)
                [^"\\]+    # Gobble all non double quotes and backslashes
            )
        |
            \\.            # Backslash followed by any character
        )*
    "
    }xg;                   # /x modifier allows whitespace and comments.