正则表达式重定义错误
我在使用Python的时候遇到了重定义错误。我知道这是因为重定义,但从逻辑上讲,应该不可能出现这种情况,因为这是一个“或”的关系。有没有什么办法可以解决这个问题?提前感谢任何帮助。
/python-2.5/lib/python2.5/re.py", 第233行,在_compile中 raise error, v # 无效的表达式 sre_constants.error: 组名'id'的重定义,作为组9;之前是组6
import re
DOB_RE = "(^|;)DOB +(?P<dob>\d{2}-\d{2}-\d{4})"
ID_RE = "(^|;)ID +(?P<id>[A-Z0-9]{12})"
INFO_RE = "- (?P<info>.*)"
PERSON_RE = "((" + DOB_RE + ".*" + ID_RE + ")|(" + \
ID_RE + ".*" + DOB_RE + ")|(" + \
DOB_RE + "|" + ID_RE + ")).*(" + INFO_RE + ")*"
PARSER = re.compile(PERSON_RE)
samplestr1 = garbage;DOB 10-10-2010;more garbage\nID PARI12345678;more garbage
samplestr2 = garbage;ID PARI12345678;more garbage\nDOB 10-10-2010;more garbage
samplestr3 = garbage;DOB 10-10-2010
samplestr4 = garbage;ID PARI12345678;more garbage- I am cool
3 个回答
在这种情况下,可能更好的是遍历一组常规表达式。
>>> strs=[
... "garbage;DOB 10-10-2010;more garbage\nID PARI12345678;more garbage",
... "garbage;ID PARI12345678;more garbage\nDOB 10-10-2010;more garbage",
... "garbage;DOB 10-10-2010",
... "garbage;ID PARI12345678;more garbage- I am cool"]
>>> import re
>>>
>>> DOB_RE = "(^|;|\n)DOB +(?P<dob>\d{2}-\d{2}-\d{4})"
>>> ID_RE = "(^|;|\n)ID +(?P<id>[A-Z0-9]{12})"
>>> INFO_RE = "(- (?P<info>.*))?"
>>>
>>> REGEX = map(re.compile,[DOB_RE + ".*" + ID_RE + "[^-]*" + INFO_RE,
... ID_RE + ".*" + DOB_RE + "[^-]*" + INFO_RE,
... DOB_RE + "[^-]*" + INFO_RE,
... ID_RE + "[^-]*" + INFO_RE])
>>>
>>> def get_person(s):
... for regex in REGEX:
... res = re.search(regex,s)
... if res:
... return res.groupdict()
...
>>> for s in strs:
... print get_person(s)
...
{'dob': '10-10-2010', 'info': None, 'id': 'PARI12345678'}
{'dob': '10-10-2010', 'info': None, 'id': 'PARI12345678'}
{'dob': '10-10-2010', 'info': None}
{'info': 'I am cool', 'id': 'PARI12345678'}
我本来打算用pyparsing的Each类来举个例子,这个类可以处理顺序不固定的表达式,但后来我发现里面有些混乱的内容,所以用searchString
来搜索你的字符串似乎更合适。这让我很感兴趣,因为searchString
会返回一系列的ParseResults,每个匹配的结果都会有一个(包括任何对应的命名结果)。我想,“如果我把返回的ParseResults用sum合并一下,那真是个黑科技!”呃,应该说“真是个新奇的想法!”所以这里有一个前所未见的pyparsing小技巧:
from pyparsing import *
# define the separate expressions to be matched, with results names
dob_ref = "DOB" + Regex(r"\d{2}-\d{2}-\d{4}")("dob")
id_ref = "ID" + Word(alphanums,exact=12)("id")
info_ref = "-" + restOfLine("info")
# create an overall expression
person_data = dob_ref | id_ref | info_ref
for test in (samplestr1,samplestr2,samplestr3,samplestr4,):
# retrieve a list of separate matches
separate_results = person_data.searchString(test)
# combine the results using sum
# (NO ONE HAS EVER DONE THIS BEFORE!)
person = sum(separate_results, ParseResults([]))
# now we have a uber-ParseResults object!
print person.id
print person.dump()
print
输出结果是:
PARI12345678
['DOB', '10-10-2010', 'ID', 'PARI12345678']
- dob: 10-10-2010
- id: PARI12345678
PARI12345678
['ID', 'PARI12345678', 'DOB', '10-10-2010']
- dob: 10-10-2010
- id: PARI12345678
['DOB', '10-10-2010']
- dob: 10-10-2010
PARI12345678
['ID', 'PARI12345678', '-', ' I am cool']
- id: PARI12345678
- info: I am cool
不过我也懂正则表达式。这是用re库的类似方法。
import re
# define each individual re, with group names
dobRE = r"DOB +(?P<dob>\d{2}-\d{2}-\d{4})"
idRE = r"ID +(?P<id>[A-Z0-9]{12})"
infoRE = r"- (?P<info>.*)"
# one re to rule them all
person_dataRE = re.compile('|'.join([dobRE, idRE, infoRE]))
# using findall with person_dataRE will return a 3-tuple, so let's create
# a tuple-merger
merge = lambda a,b : tuple(aa or bb for aa,bb in zip(a,b))
# let's create a Person class to collect the different data bits
# (or if you are running Py2.6, use a namedtuple
class Person:
def __init__(self,*args):
self.dob, self.id, self.info = args
def __str__(self):
return "- id: %s\n- dob: %s\n- info: %s" % (self.id, self.dob, self.info)
for test in (samplestr1,samplestr2,samplestr3,samplestr4,):
# could have used reduce here, but let's err on the side of explicity
persontuple = ('','','')
for data in person_dataRE.findall(test):
persontuple = merge(persontuple,data)
# make a person
person = Person(*persontuple)
# print out the collected results
print person.id
print person
print
输出结果是:
PARI12345678
- id: PARI12345678
- dob: 10-10-2010
- info:
PARI12345678
- id: PARI12345678
- dob: 10-10-2010
- info:
- id:
- dob: 10-10-2010
- info:
PARI12345678
- id: PARI12345678
- dob:
- info: I am cool
正则表达式的语法不允许使用多个同名的分组,也就是说,如果有一些分组没有被“匹配到”,它们就会被认为是“空的”(也就是None)。
所以你需要把这些分组的名字改一下,比如改成 dob0
、dob1
、dob2
,还有 id0
、id1
、id2
。这样做之后,你就可以很方便地把这些键合并成你想要的字典了,前提是你已经从匹配中得到了一个分组字典。
比如,可以把 DOB_RE
改成一个函数,而不是一个常量,比如这样:
def DOB_RE(i): return "(^|;)DOB +(?P<dob%s>\d{2}-\d{2}-\d{4})" % i
其他的也可以类似处理,并且在计算 PERSON_RE
的时候,把三次出现的 DOB_RE
改成 DOB_RE(0)
、DOB_RE(1)
等等(其他的也一样处理)。