Каков будет правильный подход, чтобы найти и отформатировать неофициально написанную дату в строке? - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть небольшой проект, в котором даты неформально записаны в базе данных Firebase в виде строк. Мне нужно было бы превратить эти даты в формат даты и времени. Это при условии, что даты действительны. Входные данные на сайте не могут быть изменены (вот и вся предпосылка решения этой проблемы). Также предполагается, что месяцы написаны по имени, а месяцы в формате ГГГГ.

Я классифицировал некоторые примеры этих записей:

Почти явно:

«13 июля 2017», «3 декабря 2008», «декабрь 2016», «21 декабря 2017», «2020», «24 ноября 2017», «14 марта 2012», «22 июля 2016», «20 февраль 2012 "," 17 января 2011 "," полученный июль 2013 "...

Это было бы относительно легко. Год всегда представляет собой четырехзначное число, дата - двузначное число, а месяц - строку. Их можно проверить / сравнить, и если они пропускают точную дату (1 или 2 цифры), я могу предположить, что она может быть указана как первая (день месяца), то же самое относится и к определенным месяцам (предположительно, в январе).

Другие простые строки:

«Когда группа готова», «Не указано», «Отменено», «установлено».

Они не содержат даты, поэтому они не важны. Только проверка на отсутствие номеров делает работу. Они могут быть установлены как 00-00-0000, не имеет значения.

Сложнее:

«В течение 12 или 24 месяцев», «4 квартал 2013 года», «Поздняя осень 2019 года»

Я думал:

Если я читаю «в пределах», я вычисляю текущую дату плюс число, за которым следует (дни, месяцы, годы).

Если я определю Q (четверти) как карту

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

и слова

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

То же самое относится и к сезонам.

Я мог бы получить доступ, например, к 4-му элементу Q для четвертого квартала и получить его месяцы или позднюю весну как сезоны ["весна"] и получить месяц "ранний, средний, поздний".

Вернуться к вопросу:

Я не уверен, что мне следует подходить к этому, используя регулярные выражения, карты и так много сравнений, которые будут вводить много ошибок, или использовать какой-то ИИ, но я не слишком опытный в предмете пока.

Итак, вернемся к вопросу, как бы вы подошли к такой проблеме?

Есть ли какая-нибудь библиотека, которая может помочь?

Мне кажется, что здесь не очень простая реализация, или известные мне подходы неэффективны и требуют много жесткого кодирования.

1 Ответ

0 голосов
/ 11 декабря 2018

Вот что я сделал.На случай, если кому-то понадобится решить проблему, подобную этой.

Этот код можно оптимизировать, но у меня просто не было времени atm.

Предполагается: дата в формате [что угодно] DD [что угодно] месяц (письменно) [что угодно] ГГГГ

Предполагается: если день не указан, число 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...