Regex 在perl中使用正则表达式从上次出现的匹配

Regex 在perl中使用正则表达式从上次出现的匹配,regex,perl,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 my $regexp = qr!\*/(?>(.*?)////RESULT)!s; ... my $match = ($s

我有这样一个文本:

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
my $regexp = qr!\*/(?>(.*?)////RESULT)!s;
...
my $match = ($string =~ /^.*$regexp$some_other_regexp/s);
文本是多行的,我需要从上次出现的“*/”中提取,直到“///RESULT”。在这种情况下,结果应为:

 select this part on
ly 
 select this part on
ly 
如何在perl中实现这一点

我尝试了
\\*/(.\124;\ n)*///结果
,但这将从第一个“*/”开始

这里有一个选项:

use strict;
use warnings;

my $string = <<'END';
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
END

my ($segment) = $string =~ m!\*/([^/]+)////RESULT$!s;

print $segment;
匹配不包含
字符串的任意数量的字符。它类似于
[^a]
,但用于字符串而不是字符

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

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ ). )* )
    ////RESULT
    (?: (?! \*/ ). )*
    \z
}xs;
如果您不在乎
*/
是否出现在
////RESULT
之后,那么以下是最安全的:

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ ). )* )
    ////RESULT
}xs;
如果在最后一个
*/
后面有两个
///RESULT
,您没有指定应该发生什么。以上匹配到最后一个。如果你想匹配到第一个,你可以使用

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

在这种情况下,一个有用的技巧是在regexp前面加上贪婪模式
*
,这将尝试在其余模式匹配之前匹配尽可能多的字符。因此:

my ($match) = ($string =~ m!^.*\*/(.*?)////RESULT!s);
让我们将此模式分解为以下组件:

  • ^.*
    从字符串开头开始,并尽可能多地匹配字符。(
    s
    修饰符允许
    甚至匹配换行符。)字符串锚点的开头
    ^
    不是严格必需的,但它确保了如果匹配失败,regexp引擎不会浪费太多时间回溯

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

  • (.*)
    匹配并捕获任意数量的字符;
    使其取消冻结,因此它倾向于匹配尽可能少的字符,以防有多个位置可以匹配剩余的regexp

  • 最后,
    ///RESULT
    只匹配自身

由于该模式包含很多斜杠,而且我想避免使用斜杠,所以我决定使用替代的regexp分隔符。感叹号(
)是一种流行的选择,因为它们不会与任何正常的regexp语法冲突


Edit:根据下面与ikegami的讨论,我想我应该注意,如果您想在较长的regexp中使用此regexp作为子模式,并且如果您想保证由
(.*?
匹配的字符串永远不会包含
///RESULT
,那么您应该将regexp的这些部分封装在

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
my $regexp = qr!\*/(?>(.*?)////RESULT)!s;
...
my $match = ($string =~ /^.*$regexp$some_other_regexp/s);

(?>)
会导致其中的模式失败,而不是接受次优匹配(即超出第一个子字符串匹配
///RESULT
)的模式,即使这意味着剩余的regexp将无法匹配。

您尝试了什么?我尝试了\*/(.|\n)*////结果,但这将从第一个“*/”开始谢谢,请您解释一下是什么原因!在m之后,什么是[^/]?这不允许在
*/
////RESULT
之间有任何
/
。(它也不能保证匹配最后一个
*/
,但这可能不是问题。)@PeitiPeterLi-因为字符串中有前斜杠,
m用于匹配。注意,使用了
m{}
[]
表示一个字符集,
[^/]
表示不(
^
)正斜杠。@ikegami-Yes——关于正则表达式,除了捕获中的/。我把这个问题简单化了。永远感谢你的评论。谢谢。我讨厌
*?
。它不能保证不匹配你希望它不匹配的东西。在这个特定的模式中,它工作得非常好,只是如果它出现在
///RESULT
之后,它与lat
*///code>不匹配。不过这可能是件好事。@ikegami:实际上,
*?
的行为定义得很好;看,我从来没说过它没有定义。我很熟悉它的功能,它的用途,这两者不是一回事。给我看一个模式,有两个代码> *.< /代码>,我会告诉你一个bug或一个无用的<代码> <代码>(性能除外)。给出了一个1的解释,即使我认为你的答案不可维护。如果“您希望”它会做的是“匹配除紧跟其后的模式之外的任何东西”,那么不,它不会这样做(尽管您可以通过在
(?>)
中包装它和它后面的模式来获得这种效果)。我并不是真的不同意你的观点,我只是认为正确的答案不是“不要使用
*?
”而是“除非你理解它的作用,否则不要使用
*?
”。