使用perl中的regex匹配上次出现的事件

Pei*_* Li 10 regex perl

我有这样的文字:

hello world /* select a from table_b
*/ some other text with new line cha
racter and there are some blocks of 
/* any string */ select this part on
ly 
////RESULT rest string
Run Code Online (Sandbox Code Playgroud)

文本是多行的,我需要从最后一次出现的"*/"中提取,直到"//// RESULT".在这种情况下,结果应该是:

 select this part on
ly 
Run Code Online (Sandbox Code Playgroud)

如何在perl中实现这一目标?

我试过\\\*/(.|\n)*////RESULT但是从第一个"*/"开始

Ilm*_*nen 18

在这种情况下,一个有用的技巧是在regexp前加上贪婪模式.*,在模式的其余部分匹配之前,它会尝试匹配尽可能多的字符.所以:

my ($match) = ($string =~ m!^.*\*/(.*?)////RESULT!s);
Run Code Online (Sandbox Code Playgroud)

让我们将这种模式分解为其组成部分:

  • ^.*从字符串的开头开始,尽可能多地匹配字符.(s修饰符允许.匹配甚至换行.)字符串开头锚点^并不是绝对必要的,但它确保正则表达式引擎在匹配失败时不会浪费太多时间回溯.

  • \*/只匹配文字字符串*/.

  • (.*?)匹配并捕获任意数量的字符; 将?使得ungreedy,所以喜欢的情况下,几个字符地匹配有不止一个位置,正则表达式的其余部分可以匹配.

  • 最后,////RESULT只是匹配自己.

由于该模式包含很多斜线,并且因为我想避免倾斜牙签综合症,所以我决定使用替代的regexp分隔符.感叹号(!)是一种流行的选择,因为它们不会与任何正常的正则表达式语法冲突.


编辑:每下面池上的讨论,我想我应该注意的是,如果你想使用这个正则表达式作为子模式在一个较长的正则表达式,如果你想保证通过匹配的字符串(.*?)永远不会包含////RESULT,那么你应该将regexp的那些部分包装在一个独立的(?>)子表达式中,如下所示:

my $regexp = qr!\*/(?>(.*?)////RESULT)!s;
...
my $match = ($string =~ /^.*$regexp$some_other_regexp/s);
Run Code Online (Sandbox Code Playgroud)

(?>)原因它里面的图案以失败而不是接受一个次优匹配(即,一个延伸超出所述第一子串匹配////RESULT),即使这意味着,正则表达式的其余部分将不匹配.


ike*_*ami 5

(?:(?!STRING).)*
Run Code Online (Sandbox Code Playgroud)

匹配任意数量的不包含STRING. 就像[^a], 但用于字符串而不是字符。

如果您知道不会遇到某些输入(如 Kenosis 和 Ilmari Karonen 所做的那样),您可以采取快捷方式,但这与您指定的内容相匹配:

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ ). )* )
    ////RESULT
    (?: (?! \*/ ). )*
    \z
}xs;
Run Code Online (Sandbox Code Playgroud)

如果您不在乎是否*/出现在 之后////RESULT,以下是最安全的:

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ ). )* )
    ////RESULT
}xs;
Run Code Online (Sandbox Code Playgroud)

您没有指定如果////RESULT最后一个*/. 以上匹配直到最后一个。如果你想匹配到第一个,你会使用

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ | ////RESULT ). )* )
    ////RESULT
}xs;
Run Code Online (Sandbox Code Playgroud)