【问题标题】:Understanding Perl regular expression modifers /m and /s [duplicate]了解 Perl 正则表达式修饰符 /m 和 /s [重复]
【发布时间】:2014-05-22 15:46:47
【问题描述】:

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

但我对修饰符 s 和 m 感到困惑。任何人都可以用代码示例解释 s 和 m 之间的区别以显示它如何不同吗?我试图在网上搜索,它只给出了链接http://perldoc.perl.org/perlre.html#Modifiers中的解释。在 stackoverflow 中,我什至看到人们一起使用 s 和 m。 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"

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    你链接到自己的documentation 对我来说似乎很清楚。如果您能解释一下您在理解它时遇到了什么问题,以及您如何认为 /s/m 是对立的,这将有所帮助。

    非常简单地说,/s 改变了点元字符 . 的行为,使其完全匹配任何字符。通常它匹配除换行符"\n" 之外的任何内容,因此即使字符串包含换行符,它也会将字符串视为s单行。

    /m 修改插入符号^ 和美元$ 元字符,以便它们匹配字符串 的换行符,将其视为m多行细绳。通常它们只会在字符串的开头和结尾匹配。

    您不应该对 /g 修饰符“贪婪”感到困惑。它用于 global 匹配,它将在字符串中找到 所有 出现的模式。 greedy 一词通常用于表示模式中 量词的行为。例如,.* 被认为是贪婪的,因为它会匹配尽可能多的字符,而 .*? 会匹配尽可能少的字符。


    更新

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

    将其更改为 /".*"/sg 会稍微改进一点,因为 . 现在可以匹配每行末尾的换行符,因此该模式可以匹配多行字符串。 (请注意,这里的 object 字符串被认为是 "single line" - 即匹配行为就好像其中没有换行符一样,直到 @涉及到 987654339@。)这里是 greedy 的传统含义,因为该模式现在匹配从第一行的第一个双引号到最后一个双引号的所有内容。线。我想这不是你想要的。

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

    看看这个程序及其输出,注意我在每场比赛的开头都放了一个雪佛龙&gt;&gt;,以便区分它们

    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 \"""。解决这个问题可能比你想的要复杂,但这是完全可能的。如果您也需要修复,请说出来。


    更新

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

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

    【讨论】:

    • 感谢您的解释。但是,我无法使用 m 匹配多行。介意解释编辑问题中的代码。
    • 正则表达式总是可以匹配多行字符串。 m 修饰符只是意味着它将字符串识别为多行(为了匹配锚点,^$)。但不要过多解读名称,multilinesingle-line。它们是本不应该存在的模式的坏名字。在 Perl 6 中,它们已被淘汰。
    • 所以当我使用/s 时,它会改变. 的行为,因此. 将包含\n 作为. 的一部分。我说的对吗?
    • +1 表示彻底彻底。 :)
    • 嗨,鲍罗丁。我认为您的说法至少对于像我这样的新手来说有点误导。我花了整整一个下午在这个网站上提问,以确定我们必须使用 0777 选项进行多行替换,对吗?但是您说“匹配多行”而没有提及0777
    【解决方案2】:

    /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
    

    【讨论】:

      【解决方案3】:

      /".*"/mg 你的对手

      1. "开头
      2. 然后.*" 尽可能匹配每个字符(\n 除外)直到"
      3. 由于您使用/g 并且匹配在第二个" 停止,正则表达式将尝试重复前两个步骤
      4. /m 在这里没有区别,因为您没有使用 ^$

      由于您在示例中对引号进行了转义,因此正则表达式不是执行您想要的最佳工具。 如果不是这种情况,并且您想要两个引号之间的所有内容,/".*?"/gs 就可以完成这项工作。

      【讨论】:

      • 感谢您的解释。能否给出一个代码示例来演示/m是如何使用的?
      • @user2763829 eval.in/134452
      【解决方案4】:

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

      但是,反斜杠也可以自行转义。当一个字符串中包含 windows 路径时会出现这种情况,因此以下正则表达式会捕捉到这种情况:

      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.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-27
        相关资源
        最近更新 更多