如何在字符串中搜索正则表达式模式的重叠匹配

4

我有一个字符串

my $line = "MZEFSRGGRMEAZFE*MQZEFFMAEZF*"

我希望找到每一个以M开头、以*结尾的子字符串,并将其添加到一个数组中。这意味着以上字符串会在我的数组中生成6个元素。

以下是我的代码:

foreach ( $line =~ m/M.*?\*/g ) {
    push @ORF, $_;
}

但是它只给了我两个元素,因为它忽略了重叠的字符串。

有没有办法获取所有匹配项?我尝试过谷歌搜索,但找不到答案。

2个回答

4

可以使用re中的代码回溯控制字符来实现一些魔法:

#!/usr/bin/env perl

use strict;
use warnings;

my $line = "MZEFSRGGRMEAZFE*MQZEFFMAEZF*";

local our @match;

$line =~ m/(M.*\*)(?{ push @match, $1 })(*FAIL)/;

use Data::Dump;

dd @match;

输出:

(
  "MZEFSRGGRMEAZFE*MQZEFFMAEZF*",
  "MZEFSRGGRMEAZFE*",
  "MEAZFE*MQZEFFMAEZF*",
  "MEAZFE*",
  "MQZEFFMAEZF*",
  "MAEZF*",
)

1
应该写成local our @match;,否则如果放在被多次调用的子程序中,它将会失败。 - ikegami

1
我不相信可以创建一个正则表达式模式来匹配所有这样的子字符串,因为你要求同时进行贪婪和非贪婪匹配,以及其他所有中间内容。
我建议您存储所有可能的子字符串的起始和结束位置,并使用双重循环将所有起始位置与所有结束位置组合起来。
此程序演示了。
use strict;
use warnings 'all';
use feature 'say';

my $line = 'MZEFSRGGRMEAZFE*MQZEFFMAEZF*';

my @orf;

{
    my (@s, @e);
    push @s, $-[0] while $line =~/M/g;
    push @e, $+[0] while $line =~/\*/g;

    for my $s ( @s ) {
        for my $e ( @e ) {
            push @orf, substr $line, $s, $e-$s if $e > $s;
        }
    }
}

say for @orf;

输出

MZEFSRGGRMEAZFE*
MZEFSRGGRMEAZFE*MQZEFFMAEZF*
MEAZFE*
MEAZFE*MQZEFFMAEZF*
MQZEFFMAEZF*
MAEZF*

谢谢!我以为有更简单的方法来做这件事。 - cachemoi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接