【问题标题】:How to search for overlapping matches for a regex pattern within a string如何在字符串中搜索正则表达式模式的重叠匹配
【发布时间】:2016-02-16 06:20:40
【问题描述】:

我有这个字符串

my $line = "MZEFSRGGRMEAZFE*MQZEFFMAEZF*"

我想找到以M 开头并以* 结尾的每个子字符串,并将其添加到数组中。这意味着上面的字符串会给我的数组中的 6 个元素。

我有这个代码

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

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

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

【问题讨论】:

    标签: arrays regex string perl


    【解决方案1】:

    可以使用code within reBacktracking control verbs 来获得一点魔法:

    #!/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*",
    )
    

    【讨论】:

    • 那真的应该是local our @match;,否则如果放在一个被多次调用的子程序中就会失败。
    【解决方案2】:

    我认为不可能创建一个匹配所有此类子字符串的单个正则表达式模式,因为您同时要求 both 贪婪和非贪婪匹配,以及介于两者之间的所有其他内容

    我建议您存储这些子字符串的所有可能的开始和结束位置,并使用双循环将所有开始位置与所有结束位置结合起来

    这个程序演示

    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*
    

    【讨论】:

    • 谢谢!我认为会有更简单的方法来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-16
    • 1970-01-01
    • 2015-11-14
    • 2017-11-10
    相关资源
    最近更新 更多