我在日期中有以下要求,可以是以下任何一种格式。
mm / dd / yyyy或dd Mon YYYY
下面显示的例子很少 2009年4月20日和2001年1月24日
为了解决这个问题,我写了正则表达式,如下所示
下面列出了很少的文字场景
txt1 = 'Lithium 0.25 (7/11/77). LFTS wnl. Urine tox neg. Serum tox + fluoxetine 500; otherwise neg. TSH 3.28. BUN/Cr: 16/0.83. Lipids unremarkable. B12 363, Folate >20. CBC: 4.9/36/308 Pertinent Medical Review of Systems Constitutional:
“txt2 =“s患者是一名44岁的已婚白人女性, 失业的装饰员,和丈夫一起生活,照顾两个年轻人 儿童,由国会山医院PCP转介,Heather博士 Zubia,在第一次访问托尼博士之前进行紧急评估/治疗 Winkler在2001年1月24日的八个星期。“
date = re.findall(r'(?:\b(?<!\.)[\d{0,2}]+)'
'(?:[/-]\d{0,}[/-]\d{2,4}) | (?:\b(?<!\.)[\d{1,2}]+)[th|st|nd]*'
' (?:[Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec][a-z]*) \d{2,4}', txtData)
我没有得到2001年1月24日,好像我单独运行(?:\b(?<!\.)[\d{1,2}]+)[th|st|nd]* (?:[Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec][a-z]*) \d{2,4}'
我能够得到输出。
问题1:上述表达式中的错误是什么?
问题2:我想将两者结合起来使其更具可读性,因为我必须解析任何其他格式,所以我使用了如下所示的连接
RE1 = '(?:\b(?<!\.)[\d{0,2}]+) (?:[/-]\d{0,}[/-]\d{2,4})'
RE2 = '(?:\b(?<!\.)[\d{1,2}]+)[th|st|nd]* (?:[Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec][a-z]*) \d{2,4}'
regex_all = '|'.join([RE1, RE2])
regex_all = re.compile(regex_all)
date = regex_all.findall(txtData) // notice here txtData can be any one of the above string.
在上述情况下,我的输出为NaN。
如果我加入,请说明错误是什么。
感谢您的帮助。
答案 0 :(得分:2)
请注意,加入在字符串中的同一位置也匹配的长模式是一个非常糟糕的主意。这将导致正则表达式引擎回溯太多,并可能导致崩溃和减速。如果有办法重新编写交替,以便它们只能在不同位置匹配,甚至完全摆脱它们,那就去做吧。
此外,您应该使用分组构造(...)
对模式序列进行分组,并在需要匹配特定字符时仅使用[...]
个字符类。
此外,您的替代方案是重叠的,您可以轻松地将它们组合起来。请参阅固定的正则表达式:
\b(?<!\.)\d{1,2}(?:[/-]\d+[/-]|(?:th|st|[nr]d)?\s*(?:(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*))\s*(?:\d{4}|\d{2})\b
请参阅regex demo。
<强>详情
\b
- 字边界(?<!\.)
- 紧靠当前位置左侧的.
\d{1,2}
- 1或2位数字(?:
- 非捕获交替组的开始:
[/-]\d+[/-]
- /
或-
,1位数,-
或/
|
- 或(?:th|st|[nr]d)?\s*(?:
(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*))
- th
,st
,nd
或rd
(可选),后跟0 +空格,然后是月份名称\s*
- 0+ whitespaces (?:\d{4}|\d{2})
- 2位或4位\b
- 尾随字边界。另一个注意事项:如果要将类似日期的字符串与两个匹配的分隔符匹配,则需要捕获第一个分隔符,并使用反向引用来匹配第二个分隔符,请参阅this regex demo。在Python中,您需要re.finditer
才能获得这些匹配。
请参阅this Python demo:
import re
rx = r"\b(?<!\.)\d{1,2}(?:([/-])\d+\1|(?:th|st|[nr]d)?\s*(?:(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*))\s*(?:\d{4}|\d{4})\b"
s = "Lithium 0.25 (7/11/77). LFTS wnl. Urine tox neg. Serum tox\nfluoxetine 500; otherwise neg. TSH 3.28. BUN/Cr: 16/0.83. Lipids unremarkable. B12 363, Folate >20. CBC: 4.9/36/308 Pertinent Medical\nReview of Systems Constitutional:\n\nThe patient is a 44 year old married Caucasian woman, unemployed Decorator, living with husband and caring for two young children, who is referred by Capitol Hill Hospital PCP, Dr. Heather Zubia, for urgent evaluation/treatment till first visit with Dr. Toney Winkler IN EIGHT WEEKS on 24 Jan 2001"
print([x.group(0) for x in re.finditer(rx, s, re.I)])
# => ['7/11/77', '24 Jan 2001']
答案 1 :(得分:1)
r'(?:\b(?<!\.)[\d{0,2}]+)'
'(?:[/-]\d{0,}[/-]\d{2,4}) | (?:\b(?<!\.)[\d{1,2}]+)[th|st|nd]*'
' (?:[Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec][a-z]*) \d{2,4}'
r'foo'
),而不仅仅是第一个字符串。这样反斜杠(\)将被视为普通字符,可供re
库使用。[abc|def]
匹配[]
之间的任何字符,而(one|two|three)
匹配任何表达式(one
,two
或three
)答案 2 :(得分:1)
我认为你的方法太复杂了。我建议使用简单的正则表达式和strptime()
的组合。
import re
from datetime import datetime
date_formats = ['%m/%d/%Y', '%d %b %Y']
pattern = re.compile(r'\b(\d\d?/\d\d?/\d{4}|\d\d? \w{3} \d{4})\b')
data = "... your string ..."
for match in re.findall(pattern, data):
print("Trying to parse '%s'" % match)
for fmt in date_formats:
try:
date = datetime.strptime(match, fmt)
print(" OK:", date)
break
except:
pass
这种方法的优点是,除了更容易管理的正则表达式之外,它不会选择看似合理但不存在的日期,例如2/29/2000
(而2/29/2004
可以工作)。