结合编译的Python正则表达式

时间:2018-02-23 22:21:01

标签: python regex

Python中是否有用于组合编译正则表达式的机制?

我知道可以通过从现有模式对象中提取普通旧字符串.pattern属性来编译新表达式。但这在几个方面失败了。例如:

import re

first = re.compile(r"(hello?\s*)")

# one-two-three or one/two/three - but not one-two/three or one/two-three
second = re.compile(r"one(?P<r1>[-/])two(?P=r1)three", re.IGNORECASE)

# Incorrect - back-reference \1 would refer to the wrong capturing group now,
# and we get an error "redefinition of group name 'r1' as group 3; was 
# group 2 at position 47" for the `(?P)` group.
# Result is also now case-sensitive, unlike 'second' which is IGNORECASE
both = re.compile(first.pattern + second.pattern + second.pattern)

我正在寻找的结果可以在Perl中实现:

$first = qr{(hello?\s*)};

# one-two-three or one/two/three - but not one-two/three or one/two-three
$second = qr{one([-/])two\g{-1}three}i;

$both = qr{$first$second$second};

测试显示结果:

test($second, "...one-two-three...");                   # Matches
test($both, "...hello one-two-THREEone-two-three...");  # Matches
test($both, "...hellone/Two/ThreeONE-TWO-THREE...");    # Matches
test($both, "...HELLO one/Two/ThreeONE-TWO-THREE...");  # No match

sub test {
  my ($pat, $str) = @_;
  print $str =~ $pat ? "Matches\n" : "No match\n";
}

是否有某个库可以在Python中使用这个用例?或者我在某个地方缺少一个内置功能?

(注意 - 上面的Perl正则表达式中的一个非常有用的功能是\g{-1},它明确地引用了前一个捕获组,因此当我尝试使用时,Python没有抱怨这种类型的冲突编译组合表达式。我在Python世界的任何地方都没有看到,不确定是否有一个我没有想过的替代方案。)

2 个答案:

答案 0 :(得分:2)

肯,这是一个有趣的问题。我同意您的看法,Perl解决方案非常出色。 我想出了一些东西,但它并不那么优雅。也许它为您提供了一些使用Python进一步探索解决方案的想法。这个想法是使用Python re方法来模拟串联。

first = re.compile(r"(hello?\s*)")
second = re.compile(r"one(?P<r1>[-/])two(?P=r1)three", re.IGNORECASE)

str="...hello one-two-THREEone/two/three..."
#str="...hellone/Two/ThreeONE-TWO-THREE..."
if re.search(first,str):
    first_end_pos = re.search(first,str).end()
    if re.match(second,str[first_end_pos:]):
        second_end_pos = re.match(second,str[first_end_pos:]).end() + first_end_pos
        if re.match(second,str[second_end_pos:]):
            print ('Matches')

它适用于大多数情况,但不适用于以下情况:

...hellone/Two/ThreeONE-TWO-THREE...

所以,是的,我承认这不是您问题的完整解决方案。希望这会有所帮助。

答案 1 :(得分:-1)

我不是perl专家,但看起来你并不比较苹果和苹果。你在python中使用了命名捕获组,但是在perl示例中我没有看到任何命名的捕获组。这会导致你提到的错误,因为这个

both = re.compile(first.pattern + second.pattern + second.pattern)

尝试创建两个名为r1

的捕获组

例如,如果您使用下面的正则表达式,那么尝试按名称访问group_one,您是否会获得#34之前的数字;某些文本&#34;还是之后?

# Not actually a valid regex
r'(?P<group_one>[0-9]*)some text(?P<group_one>[0-9]*)'

解决方案1 ​​

一个简单的解决方案可能是从捕获组中删除名称。同时将re.IGNORECASE添加到both。下面的代码有效,但我不确定生成的正则表达式模式是否与您希望匹配的匹配。

first = re.compile(r"(hello?\s*)")
second = re.compile(r"one([-/])two([-/])three", re.IGNORECASE)
both = re.compile(first.pattern + second.pattern + second.pattern, re.IGNORECASE)

解决方案2

我可能会做的是将单独的正则表达式定义为字符串,然后您可以将它们组合起来,但是您喜欢。

pattern1 = r"(hello?\s*)"
pattern2 = r"one([-/])two([-/])three"
first = re.compile(pattern1, re.IGNORECASE)
second = re.compile(pattern2, re.IGNORECASE)
both = re.compile(r"{}{}{}".format(pattern1, pattern2, pattern2), re.IGNORECASE)

或者更好的是,对于这个具体的例子,不要重复pattern2两次,只考虑它在正则表达式中重复的事实:

both = re.compile("{}({}){{2}}".format(pattern1, pattern2), re.IGNORECASE)

为您提供以下正则表达式:

r'(hello?\s*)(one([-/])two([-/])three){2}'