我有许多使用命名组和未命名组的相关正则表达式。我想将未命名的组作为位置参数插入到使用命名组选择的函数中。
例如,如果模式([abc]+)([123]+)(?P<end>[%#])
与字符串"aaba2321%"
匹配,我希望获得包含["aaba", "2321"]
的列表,但不 {{1} }
我尝试了以下内容:
"%"
假设它不会捕获命名组,因为有一个单独的方法match_obj.groups()
,仅用于获取命名组。不幸的是,groupdict
包含了命名组。
然后,我决定为它编写自己的生成器:
groups
不幸的是,命名组也可以作为编号组访问。我如何单独获得编号组?
答案 0 :(得分:1)
有一种可怕的方式来做你要求的事情。它涉及通过跨度(开始和结束索引)索引所有匹配并删除groupdict
和groups
中出现的匹配:
named = dict()
unnamed = dict()
all = mo.groups()
# Index every named group by its span
for k,v in mo.groupdict().items():
named[mo.span(k)] = v
# Index every other group by its span, skipping groups with same
# span as a named group
for i,v in enumerate(all):
sp = mo.span(i + 1)
if sp not in named:
unnamed[sp] = v
print(named) # {(8, 9): '%'}
print(unnamed) # {(4, 8): '2321', (0, 4): 'aaba'}
跨度索引的原因是必要的,因为未命名和命名的组可以具有相同的值。组的唯一唯一标识符是它的开始和结束位置,因此即使您具有相同值的组,此代码也能正常工作。这是一个演示:http://ideone.com/9O7Hpb
另一种方法是编写一个函数,按照问题中显示的形式转换正则表达式,其中所有以前未命名的正则表达式都用一些前缀和数字命名。您可以匹配此正则表达式并从groupdict
答案 1 :(得分:0)
这是一个干净的版本,使用re.regex.groupindex
:
将
(?P<id>)
定义的任何符号组名映射到组号的字典。
def grouplist(match):
named = match.groupdict()
ignored_groups = set()
for name, index in match.re.groupindex.items():
if name in named: # check twice, if it is really the named attribute.
ignored_groups.add(index)
return [group for i, group in enumerate(match.groups()) if i+1 not in ignored_groups]
m = re.match('([abc]+)([123]+)(?P<end>[%#])', "aaba2321%")
unnamed = grouplist(m)
print(unnamed)
使用groupindex
,我们可以获得命名匹配项的索引,并在构建最终的组列表时将其排除在外,在下面的代码中称为unnamed
:
import re
# ===================================================================================
# This are the current matching groups:
# ===================================================================================
regex = re.compile("(((?P<first_name>\w+)) (?P<middle_name>\w+)) (?P<last_name>\w+)")
# |-------------------- #1 ------------------|
# |------- #2 -------|
# |------ #3 ------|
# |------- #4 -------|
# |------ #5 ------|
# ===================================================================================
# But we want to have the following groups instead (regex line is identical):
# ===================================================================================
regex = re.compile("(((?P<first_name>\w+)) (?P<middle_name>\w+)) (?P<last_name>\w+)")
# |---------------- #1 (#1) -----------------|
# |- first_name (#2) -|
# |---- #2 (#3) ----|
# |- middle_name (#4)-|
# | last_name (#5) |
m = regex.match("Pinkamena Diane Pie")
为方便起见,这是我们要使用的值:
assert list(m.groups()) == [
'Pinkamena Diane', # group #1
'Pinkamena', # group #2 (first_name)
'Pinkamena', # group #3
'Diane', # group #4 (middle_name)
'Pie', # group #5 (last_name)
]
assert dict(m.groupdict()) == {
'first_name': 'Pinkamena', # group #2
'middle_name': 'Diane', # group #4
'last_name': 'Pie', # group #5
}
assert dict(m.re.groupindex) == {
'first_name': 2, # Pinkamena
'middle_name': 4, # Diane
'last_name': 5, # Pie
}
因此,我们现在可以将这些命名组的索引存储在ignored_groups
集中,以在用unnamed
填充m.groups()
时省略这些组:
named = m.groupdict()
ignored_groups = set()
for name, index in m.re.groupindex.items():
if name in named: # check twice, if it is really the named attribute.
ignored_groups.add(index)
# end if
unnamed = [group for i, group in enumerate(m.groups()) if i+1 not in ignored_groups]
# end for
print(unnamed)
print(named)
所以最终我们得到:
# unnamed = grouplist(m)
assert unnamed == [
'Pinkamena Diane', # group #1 (#1)
'Pinkamena', # group #2 (#3)
]
# named = m.groupdict()
assert named == {
'first_name': 'Pinkamena', # group #2
'middle_name': 'Diane', # group #4
'last_name': 'Pie', # group #5
}
亲自尝试示例:https://ideone.com/pDMjpP