如何匹配满足我的正则表达式模式的最短字符序列?

时间:2011-03-23 06:25:22

标签: regex perl matching

我有一个字符串"ajjjjjjjjjaab"

我想要一个与上一个"ab"相匹配的模式,而不是整个字符串,甚至是"aab"

/a.*?b/  # returns two groups

/a.??b/ # matches last aab

都没有效果。

4 个答案:

答案 0 :(得分:5)

解决问题的一个简单方法是匹配:

.*(a.*b)

第一个.*贪婪,它尽可能匹配。然后,您将获得一个捕获的组,其中包含您真正需要的匹配项($1)。请注意,这假设您匹配模式的最后一次出现。如果您在字符串末尾附近有多个.*(a.*?b),并且您希望第一个b位于最后一个a之后,则可能需要{{1}}。

答案 1 :(得分:5)

其中一个:

/a[^a]*b/
/a[^ab]*b/

如果ab实际上是更复杂的模式,可以使用以下内容:

/a(?:(?!a).)*b/s
/a(?:(?!a|b).)*b/s

如果ab代表长/复杂模式,则可以避免使用任何其他代码中的变量重复它​​们。

my $re1 = qr/a/;
my $re2 = qr/b/;

/$re1(?:(?!$re1|$re2).)*$re2/s

也可以使用子模式。

/
   (?&A) (?:(?!(?&A)|(?&B)).)* (?&B)

   (?(DEFINE)
      (?<A> a )
      (?<B> b )
   )
/xs

答案 2 :(得分:3)

默认情况下,Perl中的模式匹配最左侧,最长*。使用??*?+?会将该部分更改为Left Most,Shortest,但Left Most仍然优先。

有一种方法可以让Perl与Right Most相匹配,这可能会让你获得理想的效果,但它也会让下一个人的地狱感到困惑,因此请小心使用它。

基本思想是反转与模式匹配相关的所有内容,因此右边会变为左侧。

my $subject = 'ajjjjjjjjjaab';
my $rev_sub = reverse $subject; # reverse the string being matched.
my $result;
if ($rev_sub =~ /(b.*?a)/) {    # reverse the pattern to match.
    $result = reverse $1;       # reverse the results of the match.
}
print $result;

ikegami和Kobi提供的解决方案都为您的示例找到了类似的结果。根据您的实际模式和字符串,您可能会发现每种方法的性能都有很大差异。始终Benchmark基于您的实际需求。

*仅对匹配的直接令牌最长,不包括从左到右依次尝试的替换等。

答案 3 :(得分:0)

好的,但是然后只使用/ab/进行匹配,然后就可以了。或/a{1}b/。或?