我有这样的文字:

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

文本是多行的,我需要从上次出现的“*/”中提取出来,直到“////RESULT”为止。在这种情况下,结果应为:
 select this part on
ly

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

我已经尝试过\\\*/(.|\n)*////RESULT,但这将从第一个“*/”开始

最佳答案

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

my ($match) = ($string =~ m!^.*\*/(.*?)////RESULT!s);

让我们将这种模式分解成几个组成部分:
  • ^.*从字符串的开头开始,并匹配尽可能多的字符。 (s修饰符允许.甚至可以匹配换行符。)字符串开头的 anchor ^并非绝对必要,但可以确保如果匹配失败,则正则表达式引擎不会浪费太多时间回溯。
  • \*/仅与文字字符串*/匹配。
  • (.*?)匹配并捕获任意数量的字符; ?使它变得不太贪婪,因此,如果有多个位置可以匹配其余的regexp,则它倾向于匹配尽可能少的字符。
  • 最后,////RESULT仅与自身匹配。

  • 由于该模式包含许多斜杠,并且由于我想避免使用leaning toothpick syndrome,因此我决定使用替代的regexp分隔符。感叹号(!)是一种流行的选择,因为它们不与任何常规的regexp语法冲突。

    编辑:通过下面与ikegami的讨论,我想我应该注意的是,如果您想将此regexp用作更长的regexp中的子模式,并且要保证(.*?)匹配的字符串永远不包含////RESULT, ,则应将regexp的这些部分包装在independent (?>) subexpression中,如下所示:
    my $regexp = qr!\*/(?>(.*?)////RESULT)!s;
    ...
    my $match = ($string =~ /^.*$regexp$some_other_regexp/s);
    
    (?>)导致其中的模式失败,而不是接受次优匹配(即超出第一个子字符串匹配////RESULT的子匹配),即使这意味着其余的regexp将不匹配。

    10-04 22:18
    查看更多