我正在尝试从字符串中解析出所有日期(可能以不同的形式编写)。问题是可能有一个以d/m -y
格式写的日期,例如22/11 -12。但也可能有一个以d/m
形式写的日期,没有指定年份。如果我在此字符串中找到包含较长形式的日期,我不希望以较短的形式再次找到它。这是我的代码失败的地方,它找到了第一个日期两次(一年一次,一次没有它)。
我真的有两个问题:(1)这样做的“正确”方法是什么。我似乎从错误的角度来看待这个问题。 (2)如果我坚持这样做,这条线datestring.replace(match.group(0), '')
怎么不删除日期,所以我再也找不到了?
这是我的代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
dformats = (
'(?P<day>\d{1,2})/(?P<month>\d{1,2}) -(?P<year>\d{2})',
'(?P<day>\d{1,2})/(?P<month>\d{1,2})',
'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
)
def get_dates(datestring):
"""Try to extract all dates from certain strings.
Arguments:
- `datestring`: A string containing dates.
"""
global dformats
found_dates = []
for regex in dformats:
matches = re.finditer(regex, datestring)
for match in matches:
# Is supposed to make sure the same date is not found twice
datestring.replace(match.group(0), '')
found_dates.append(match)
return found_dates
if __name__ == '__main__':
dates = get_dates('1/2 -13, 5/3 & 2012-11-22')
for date in dates:
print date.groups()
答案 0 :(得分:2)
两种方式:
使用单个正则表达式并使用|运营商将您的所有案例加在一起:
expr = re.compile ( r"expr1|expr2|expr3" )
仅查找单个实例,然后为下一次搜索传递“开始位置”。请注意,这会使事情变得复杂,因为无论选择哪种格式,您都希望始终以最早的匹配开始。即,遍历所有三个匹配,找出哪个是最早的匹配,进行替换,然后使用递增的起始位置再次执行。这使得选项1更容易,无论如何。
还有几点:
确保使用“原始字符串”:在每个字符串的前面加上“r”。否则,'\'字符可能会被吃掉而不会传递给RE引擎
考虑使用“sub”和回调函数代替“repl”参数来进行替换,而不是使用finditer。在这种情况下,“repl”传递一个匹配对象,并应返回替换字符串。
如果未选择该替代方案,则“单个”中的匹配组将具有值None,从而可以轻松检测使用的替代方案。
除非您打算修改该变量,否则不应该说“全局”。
这是一些完整的,有效的代码。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
expr = re.compile(
r'(?P<day1>\d{1,2})/(?P<month1>\d{1,2}) -(?P<year>\d{2})|(?P<day2>\d{1,2})/(?P<month2>\d{1,2})|(?P<year3>\d{4})-(?P<month3>\d{2})-(?P<day3>\d{2})')
def get_dates(datestring):
"""Try to extract all dates from certain strings.
Arguments:
- `datestring`: A string containing dates.
"""
found_dates = []
matches = expr.finditer(datestring)
for match in matches:
if match.group('day1'):
found_dates.append({'day': match.group('day1'),
'month': match.group('month1') })
elif match.group('day2'):
found_dates.append({'day': match.group('day2'),
'month': match.group('month2')})
elif match.group('day3'):
found_dates.append({'day': match.group('day3'),
'month': match.group('month3'),
'year': match.group('year3')})
else:
raise Exception("wtf?")
return found_dates
if __name__ == '__main__':
dates = get_dates('1/2 -13, 5/3 & 2012-11-22')
for date in dates:
print date
答案 1 :(得分:2)
您可以在第二个正则表达式中使用negative look ahead
仅匹配dates
未跟随的-year
: -
dformats = (
r'(?P<day>\d{1,2})/(?P<month>\d{1,2}) -(?P<year>\d{2})',
r'(?P<day>\d{1,2})/(?P<month>\d{1,2})(?!\s+-(?P<year>\d{2}))',
r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
)
因此,first
正则表达式中匹配的日期将不会与第二个匹配。
答案 2 :(得分:1)
您可以sub
代替find
:
def find_dates(s):
dformats = (
'(?P<day>\d{1,2})/(?P<month>\d{1,2}) -(?P<year>\d{2})',
'(?P<day>\d{1,2})/(?P<month>\d{1,2})',
'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
)
dates = []
for f in dformats:
s = re.sub(f, lambda m: dates.append(m.groupdict()), s)
return dates