首页 文章

多线PCRE w \ lookahead,发出计数匹配

提问于
浏览
0

我试图执行匹配的正则表达式,如果单词cat和dog都在正则表达式中以任何顺序支持多行支持

matches

cat asdjfaldsfj dog
####
does NOT match

cat adfasdf8989
####
matches

dog adlsjf88989 cat
####
matches

cat asdf8a89sdf8
a sdf asd f ads f ads fasdf
dog  a dsf ads fads f
asdfadsfadsf

我正在使用的正则表达式非常简单

/^(?=.*\bcat\b)(?=.*\bdog\b).*$/gs

问题是这只发现第一次出现,因为它是贪婪的 . 我真的希望以下计算两场比赛,但它只匹配一次

cat asdf8a89sdf8
a sdf asd f ads f ads fasdf
dog  a dsf ads fads f
asdfadsfadsf
cat asdf8a89sdf8
a sdf asd f ads f ads fasdf
dog  a dsf ads fads f
asdfadsfadsf

即使没有第二组猫STUFF狗STUFF,正则表达式仍然匹配直到结束 .

我正在使用regex101.com进行测试 .

3 回答

  • 0

    主要的问题是使用贪婪的量词 . 它's that you'重新使用 ^ 锚点以及前瞻和 .* . 该模式别无选择,只能匹配任何东西或什么都不匹配 .

    相反,只需删除前瞻方法并将 catdog 与之间的任何内容匹配,或者相反:

    /cat.*?dog|dog.*?cat/gs

    在这种情况下,您实际上需要使用 ? 指定延迟量词,否则它将像您所担心的那样将所有匹配作为一个匹配 .

    https://regex101.com/r/nv9Nj7/1

  • 0

    只是一个建议,但也许这比复杂的正则表达式更具可读性

    use List::MoreUtils 'all';
    
    my @things = qw( cat dog bird fish );
    
    for my $line ( @lines ) {
        if ( all { $line =~ / \b $_ \b /x } @things ) {
            # DO STUFF
        }
    }
    

    all 函数是List::MoreUtils的一部分,但也可在List::AllUtilsList::SomeUtils中使用

    这个实现依赖于你逐行处理你的字符串,所以你可能会做 for my line ( split(/\n/, $string) ) { ... } 之类的事情 .

  • 0

    CAustin的答案可以简化为:

    /(cat|dog).*?(?!\1)(?:cat|dog)/gs
    

    这更容易扩展到更多的字符串 . 有4个字符串:

    /(cat|dog|bird|fish).*?(?!\1)(cat|dog|bird|fish).*?(?!\1|\2)(cat|dog|bird|fish).*?(?!\1|\2|\3)(?:cat|dog|bird|fish)/gs
    

    并限制一些无用的回溯:

    /(cat|dog|bird|fish)(?>.*?(?!\1)(cat|dog|bird|fish))(?>.*?(?!\1|\2)(cat|dog|bird|fish))(?>.*?(?!\1|\2|\3)(?:cat|dog|bird|fish))/gs
    

相关问题