在字符串中查找和格式化非正式日期的正确方法是什么?

What would be the correct approach to find and format an informally written date in a string?

我有一个小项目,我在 firebase 数据库中将日期非正式地写为字符串。我需要将这些日期转换为日期时间格式。这是假设日期有效。网站中的输入不能修改(这是解决这个问题的全部前提)。还假设月份是按名称书写的,月份采用 YYYY 格式。

我对这些条目的一些示例进行了分类:

几乎露骨:

"13 july 2017", "3 december 2008", "december 2016", "21 december 2017", "2020", "24 november 2017", "14 march 2012", "22 july 2016", "20 february 2012", "17 january 2011", "obtained july 2013"...

这些会比较容易。年份始终是 4 位数字,日期是 2 位数字,月份是字符串。这些可以是 checked/compared,如果他们错过了确切的日期(1 或 2 位数字),我可以假设它可以作为第一个(一个月中的某天),同样适用于没有指定的月份(假设 1 月。 )

其他简单字符串:

"When the group is ready", "Not specified", "Canceled", "set."

这些不包含日期,因此不重要。只需检查没有数字就可以完成工作。这些可以设置为00-00-0000,没关系。

较难的:

"Within 12 or 24 months", "Q4 2013", "Late autumn 2019"

我在想:

如果我读 "within",我会计算当前日期,加上它后面的数字(天、月、年)。

如果我将Q(quarters)定义为一张地图

Q={1:(1,2,3), 2:(4,5,6), 3:(7,8,9), 4:(10,11,12)}

和单词

when = {"Early" : 1, "Mid": 2, "Late": 3}

季节也一样。

例如,我可以访问第四季度 Q 的第 4 个元素并获取它的月份,或者晚 spring 作为季节 ["spring"] 并获取 [=67= 的月份].

回到问题:

我不确定我是否应该使用正则表达式、映射和如此多的比较来解决这个问题,引入很多错误,或者使用某种 AI,但我还不太精通这门学科。

所以,回到问题,你会如何处理这类问题?

是否有任何图书馆可以提供帮助?

我觉得这里没有一个非常简单的实现,或者我知道的方法效率低下并且需要大量硬编码。

这是我所做的。如果有人需要解决这样的问题。

此代码可以优化,但我没有时间 atm。

假设:日期的格式为 [anything] DD [anything] month (written) [anything] YYYY

假设:如果未指定日期,则首选数字 1。几个月都一样。

import re
def validate_date(d,m,y):
    leap = False
    valid = False
    y = int(y)
    d = int(d)
    m = int(m)
    if(y % 400 == 0):
        leap=True
    if(y % 100 == 0):
        leap = False
    if(y % 4 == 0):
        leap = True
    if (m<13):
        if (m == 1 | m==3 | m== 5 | m==7 | m==8 | m==10 | m==12 ):
            if (d <=31):
                valid=True
        if (m == 4 | m==6 | m==9 | m==11 ):
                    if (d <= 30):
                         valid = True
        if (m==2):
            if (leap == True):
                    if (d <= 29):
                        valid = True
            if (leap == False):
                    if (d <= 28):
                        valid = True
    return valid

months = {
        1: "januari",
        2: "februari",
        3: "mars",
        4: "april",
        5: "maj",
        6: "juni",
        7: "juli",
        8: "augusti",
        9: "september",
        10: "oktober",
        11: "november",
        12: "december"
    }

def validate(date):
    month=0
    day=0
    year=0
    raw_date = str(date)
    #get the integers in the text
    raw_date = raw_date.lower()
    if (not ("q1" in raw_date or "q2" in raw_date or
             "q3" in raw_date or "q4" in raw_date)):
        if (len(re.findall('\d+', raw_date))==2):
            day, year = map(int, re.findall('\d+', raw_date))
        elif (len(re.findall('\d+', raw_date))==3):
            day, month, year = re.findall('\d+', raw_date)
    else:
        if (len(re.findall('\d+', raw_date))==2):
            quarter, year = map(int, re.findall('\d+', raw_date))
            day = 1

    #Set month to the string found, if any.
    if (month==0):
        if (months.get(1) in raw_date or ("q1" in raw_date)): month = 1
        elif(months.get(2) in raw_date): month = 2
        elif(months.get(3) in raw_date): month = 3
        elif(months.get(4) in raw_date or ("q2" in raw_date)): month = 4
        elif(months.get(5) in raw_date): month = 5
        elif(months.get(6) in raw_date): month = 6
        elif(months.get(7) in raw_date or ("q3" in raw_date)): month = 7
        elif(months.get(8) in raw_date): month = 8
        elif(months.get(9) in raw_date): month = 9
        elif(months.get(10) in raw_date or ("q4" in raw_date)): month = 10
        elif(months.get(11) in raw_date): month = 11
        elif(months.get(12) in raw_date): month = 12
        else: month = 1

    clean_date = str(str(day)+"-"+str(month)+"-"+str(year))
    # print (clean_date)
    if (validate_date(day,month,year)==False): return "00-00-0000"
    else: return str(clean_date)