连接多个正则表达式以提高可读性

2024-04-24 04:45:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下要求的日期,可以是以下任何格式。你知道吗

年/月/日或年/月/日

下面列举了几个例子 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 The 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."

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:以上表达式中的bug是什么?你知道吗

问题2:我想将两者结合起来以提高可读性,因为我必须解析任何其他格式,所以我使用了join,如下所示

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.

我得到的输出为南的情况下,上述日期。你知道吗

如果我加入,请说明有什么错误。你知道吗

谢谢你的帮助。你知道吗


Tags: alloctaprjunmarsepmayjan
3条回答

我觉得你的方法太复杂了。我建议使用简单正则表达式和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是有效的)。你知道吗

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)匹配任何表达式(onetwothree

请注意,将同样在字符串中的同一位置匹配的长模式连接起来是一个非常糟糕的主意。这将导致regex引擎回溯太多,并可能导致崩溃和减速。如果有一种方法可以重写替换项,使它们只能在不同的位置匹配,甚至可以完全删除它们,那么就这样做吧。你知道吗

此外,应该使用分组构造(...)对模式序列进行分组,并且在需要匹配特定字符时只使用[...]字符类。你知道吗

另外,你的选择是重叠的,你可以很容易地把它们结合起来。请参见固定正则表达式:

\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-单词边界
  • (?<!\.)-no.立即位于当前位置的左侧
  • \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]*))-thstndrd(可选),后跟0+空格,然后是月份名称
  • \s*-0+空格
  • (?:\d{4}|\d{2})-2或4位数字
  • \b-尾随词边界。你知道吗

另一个注意:如果您想用两个匹配的分隔符来匹配类似日期的字符串,则需要捕获第一个分隔符,并使用backreference来匹配第二个分隔符,请参见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']

相关问题 更多 >