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世界的任何地方都没有看到,不确定是否有一个我没有想过的替代方案。)
答案 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}'