【问题标题】:Get all possible matches for regex (in python)?获取正则表达式的所有可能匹配项(在 python 中)?
【发布时间】:2011-09-12 05:57:04
【问题描述】:

我有一个正则表达式,它可以以多种可能的重叠方式匹配字符串。但是,它似乎只捕获字符串中的一个可能匹配项,我怎样才能获得所有可能的匹配项?我试过 finditer 没有成功,但也许我用错了。

我要解析的字符串是:

foo-foobar-foobaz

我使用的正则表达式是:

(.*)-(.*)

>>> s = "foo-foobar-foobaz"
>>> matches = re.finditer(r'(.*)-(.*)', s)
>>> [match.group(1) for match in matches]
['foo-foobar']

我想要匹配(foo 和 foobar-foobaz),但它似乎只能得到(foo-foobar 和 foobaz)。

【问题讨论】:

标签: python regex pattern-matching


【解决方案1】:

没问题:

>>> regex = "([^-]*-)(?=([^-]*))"
>>> for result in re.finditer(regex, "foo-foobar-foobaz"):
>>>     print("".join(result.groups()))
foo-foobar
foobar-foobaz

通过将第二个捕获括号放在lookahead assertion 中,您可以捕获其内容,而不会在整个匹配中消耗它。

我还使用了[^-]* 而不是.*,因为点也与您可能不想要的分隔符- 匹配。

【讨论】:

    【解决方案2】:

    这不是正则表达式引擎往往能够做到的事情。我不知道Python是否可以。 Perl 可以使用以下内容:

    local our @matches;
    "foo-foobar-foobaz" =~ /
        ^(.*)-(.*)\z
        (?{ push @matches, [ $1, $2 ] })
        (*FAIL)
    /xs;
    

    这个特定问题可能可以通过以下技术在多种语言中使用正则表达式引擎来解决:

    my @matches;
    while ("foo-foobar-foobaz" =~ /(?=-(.*)\z)/gsp) {
       push @matches, [ ${^PREMATCH}, $1 ];
    }
    

    ${^PREMATCH} 指的是正则表达式匹配之前的内容,$1 指的是第一个 () 匹配的内容。)

    但您可以在正则表达式引擎之外轻松解决这个特定问题:

    my @parts = split(/-/, "foo-foobar-foobaz");
    my @matches;
    for (1..$#parts) {
       push @matches, [
          join('-', @parts[0..$_-1]),
          join('-', @parts[$_..$#parts]),
       ];
    }
    

    很抱歉使用 Perl 语法,但应该能够理解。欢迎翻译成 Python。

    【讨论】:

    • @user449511,添加了另一个在 Python 中应该很容易实现的方法。
    【解决方案3】:

    如果你想检测重叠匹配,你必须自己实现它——本质上,对于一个字符串foo

    1. 查找从字符串索引i 开始的第一个匹配项
    2. 针对foo[i+1:]再次运行匹配函数
    3. 对字符串中逐渐变短的剩余部分重复第 1 步和第 2 步。

    如果您使用任意长度的捕获组(例如 (.*))会变得更加棘手,因为您可能不希望 foo-foobaroo-foobar 都匹配,因此您必须进行一些额外的分析在每场比赛中移动i 甚至比+1 更远;您需要将其移动到第一个捕获的组值的整个长度,再加一个。

    【讨论】:

    • 并非如此。您可以使用前瞻断言轻松捕获重叠匹配。
    • 哦,没错。我没有想到主要是因为我处于“不改变原始模式”的心态,因此只是提出了程序化解决方案。在这里为您的答案+1。 :)
    猜你喜欢
    • 2010-10-12
    • 2013-05-09
    • 2011-10-02
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    相关资源
    最近更新 更多