2

因此,在我的 Python 脚本中,我打开了一个文本文件,其中包含格式为“1991 年 1 月 26 日”的日期

这是我的正则表达式:

pattern = """
(?:(September|April|June|November),\ (0?[1-9]|[12]\d|30),\ ((?:19|20)\d\d))#Months   with 30 days
|(?:(January|March|May|July|August|October|December),\ (0?[1-9]|[12]\d|3[01]),\ ((?:19|20)\d\d))#Months with 31 days
|(?:February, (?:(?:(0?[1-9]|1\d|2[0-8]),\ ((?:19|20)\d\d))|(?:(29),\ ((?:(?:19|20)(?:04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96))|2000))))#February with 28 days or 29 with a leap year
"""

r = re.compile(pattern, re.VERBOSE)

此正则表达式应匹配任何实际日期,包括闰年的 2 月 29 日。

我遇到的问题是想办法通过我打开的文本文件并将所有匹配的日期放入列表中。我试过使用 .match、.search、.split 和其他的,但我没有任何运气。有没有办法将所有匹配项作为字符串放入列表中,以便我可以轻松地将列表与另一个列表进行比较并找到两个列表中的所有日期?基本上我想要一个看起来像的列表

[“1990 年 1 月 1 日”,“2012 年 2 月 29 日”,“1945 年 12 月 25 日”,....]

另外,请让我知道我的正则表达式是否正确。我从另一个问题的答案修改了它,但我不确定我是否正确,因为我无法查看我的文本文件中的日期是否匹配。

4

3 回答 3

3

你没有re.findall()在你尝试过的事情列表中提到。这为您提供了所有正则表达式匹配的列表。

但是,您需要使用所有非捕获组(?:...),否则您将获得所有匹配组的列表(...)。因此,我建议

pattern = """
    (?:September|April|June|November)
    ,[ ] 
    (?:0?[1-9]|[12]\d|30)
    ,[ ]
    (?:19|20)\d\d # Months with 30 days

    |

    (?:January|March|May|July|August|October|December)
    ,[ ] 
    (?:0?[1-9]|[12]\d|3[01])
    ,[ ] 
    (?:19|20)\d\d # Months with 31 days

    |

    February
    ,[ ] 
    (?:
     (?:0?[1-9]|1\d|2[0-8])
     ,[ ] 
     (?:19|20)\d\d
    |
     29
     ,[ ] 
     (?:
      (?:19|20)
      (?:04|08|12|16|20|24|28|32|36|40|44|48|
         52|56|60|64|68|72|76|80|84|88|92|96)
     |
      2000
     )
    ) # February with 28 days or 29 with a leap year"""

但是你真的需要验证日期的正确性吗?您是否希望February, 31, 2000在您的数据中出现虚假日期?如果没有,您可以极大地简化您的正则表达式。或者至少将日期验证委托给日期解析功能,该功能比可怕的正则表达式更适合此任务。

例如:

pattern = """
    (?:January|February|March|April|May|June|
       July|August|September|October|November|December)
    ,[ ]
    [0-3]?\d
    ,[ ]
    (?:19|20)\d\d
"""

匹配诸如January, 0, 1999or之类的废话February, 31, 2000,但这真的很重要吗?

于 2012-04-25T05:54:02.490 回答
1

您可以使用简单的正则表达式进行预处理并使用datetime.strptime()函数验证日期:

import re
from datetime import datetime

def extract_date_strings(text):
    return filter(valid_date, re.findall(r"[A-Z][a-z]+, \d\d?, \d{4}", text))

def valid_date(datestr):
    try:
        return datetime.strptime(datestr, "%B, %d, %Y") #note: locale dependent
    except ValueError: 
        return None

您可以使用此代码将结果与您的测试代码进行比较。

例子

print extract_date_strings('''"January, 1, 1990", "February, 29, 2012",
     "December, 25, 1945"
     May, 40, 1945 Not a Month, 20, 1945
     February, 29, 2000 February, 29, 1900
     May, 1, 199
     ''')

输出

['January, 1, 1990', 'February, 29, 2012', 'December, 25, 1945', 
 'February, 29, 2000']
于 2012-09-16T09:29:06.353 回答
0

随机沉思:

如果您需要询问您的正则表达式是否正确,那就太复杂了。

re.VERBOSE 的想法是使您的正则表达式清晰易读,而不是附加在任何情况下都隐藏的明显注释。如果你看到 SO 水平滚动条,你的胡言乱语太长了。

如果findall不存在,您可以编写一个循环,search用于定位下一次出现的位置,以及match_object.end()argpossearch

def myfindall(regex, strg):
    alist = []
    pos = 0
    while True:
        m = regex.search(strg, pos)
        if not m: break
        alist.append(m.group(0))
        pos = m.end()
    return alist

您确定月份名称后应该有逗号吗?

于 2012-04-25T06:39:38.567 回答