从Python中编译的正则表达式中提取命名的组正则表达式模式

时间:2018-02-19 01:07:26

标签: python regex python-3.x

我在Python中有一个包含多个命名组的正则表达式。但是,如果先前的组匹配,则可能会错过与一个组匹配的模式,因为似乎不允许重叠。举个例子:

import re
myText = 'sgasgAAAaoasgosaegnsBBBausgisego'
myRegex = re.compile('(?P<short>(?:AAA))|(?P<long>(?:AAA.*BBB))')

x = re.findall(myRegex,myText)
print(x)

产生输出:

[('AAA', '')]

&#39;长&#39;小组找不到匹配因为&#39; AAA&#39;在找到前一个&#39;短片的匹配时用完了。基。

我试图找到一种允许重叠但失败的方法。作为替代方案,我一直在寻找一种分别运行每个命名组的方法。如下所示:

for g in myRegex.groupindex.keys():
    match = re.findall(***regex_for_named_group_g***,myText)

是否可以为每个命名组提取正则表达式?

最终,我想生成一个字典输出(或类似),如:

{'short':'AAA',
 'long':'AAAaoasgosaegnsBBB'}

将非常感谢任何和所有建议。

2 个答案:

答案 0 :(得分:1)

实际上似乎没有更好的方法可以做到这一点,但这是另一种方法,与this other answer一致,但有点简单。如果a)您的模式将始终形成为由管道分隔的一系列命名组,并且b)命名的组模式本身不包含命名组,则它将起作用。

如果您对每种模式的所有匹配感兴趣,以下将是我的方法。 re.split的参数查找文字管道,后跟(?=<,即命名组的开头。它编译每个子模式并使用groupindex属性来提取名称。

def nameToMatches(pattern, string):
    result = dict()
    for subpattern in re.split('\|(?=\(\?P<)', pattern):
        rx = re.compile(subpattern)
        name = list(rx.groupindex)[0]
        result[name] = rx.findall(string)
    return result

使用您给定的文本和模式,返回{'long': ['AAAaoasgosaegnsBBB'], 'short': ['AAA']}。根本不匹配的模式将为其值设置一个空列表。

如果你只需要每个模式一个匹配,你可以让它更简单一点:

def nameToMatch(pattern, string):
    result = dict()
    for subpattern in re.split('\|(?=\(\?P<)', pattern):
        match = re.search(subpattern, string)
        if match:
            result.update(match.groupdict())
    return result

这为你的数量提供了{'long': 'AAAaoasgosaegnsBBB', 'short': 'AAA'}。如果其中一个命名组完全不匹配,则它将不在dict中。

答案 1 :(得分:0)

似乎没有明显的答案,所以这是一个黑客攻击。它需要一些finessing但基本上它将原始正则表达式分成它的组成部分并在原始文本上分别运行每个组正则表达式。

import re

myTextStr = 'sgasgAAAaoasgosaegnsBBBausgisego'
myRegexStr = '(?P<short>(?:AAA))|(?P<long>(?:AAA.*BBB))'
myRegex = re.compile(myRegexStr)   # This is actually no longer needed

print("Full regex with multiple groups")
print(myRegexStr)

# Use a regex to split the original regex into separate regexes
# based on group names
mySplitGroupsRegexStr = '\(\?P<(\w+)>(\([\w\W]+?\))\)(?:\||\Z)'
mySplitGroupsRegex = re.compile(mySplitGroupsRegexStr)
mySepRegexesList = re.findall(mySplitGroupsRegex,myRegexStr)

print("\nList of separate regexes")
print(mySepRegexesList)

# Convert separate regexes to a dict with group name as key
# and regex as value
mySepRegexDict = {reg[0]:reg[1] for reg in mySepRegexesList}
print("\nDictionary of separate regexes with group names as keys")
print(mySepRegexDict)

# Step through each key and run the group regex on the original text.
# Results are stored in a dictionary with group name as key and
# extracted text as value.
myGroupRegexOutput = {}
for g,r in mySepRegexDict.items():
    m = re.findall(re.compile(r),myTextStr)
    myGroupRegexOutput[g] = m[0]

print("\nOutput of overlapping named group regexes")
print(myGroupRegexOutput)

结果输出为:

Full regex with multiple groups
(?P<short>(?:AAA))|(?P<long>(?:AAA.*BBB))

List of separate regexes
[('short', '(?:AAA)'), ('long', '(?:AAA.*BBB)')]

Dictionary of separate regexes with group names as keys
{'short': '(?:AAA)', 'long': '(?:AAA.*BBB)'}

Output of overlapping named group regexes
{'short': 'AAA', 'long': 'AAAaoasgosaegnsBBB'}

这可能对某个人有用。