После использования parsedatetime, чтобы получить структуру времени из входной строки, как можно вырезать остальную часть строки? - PullRequest
1 голос
/ 12 января 2020

Мне интересно, как использовать parsedatetime для Python, чтобы вернуть и структуру времени, и остальную часть входной строки с удалением только введенного значения даты / времени.

Пример:

import parsedatetime
p = parsedatetime.Calendar()
p.parse("Soccer with @homies at Payne Whitney at 2 pm")

возвращает:

time.struct_time(tm_year=2020, tm_mon=1, tm_mday=12, tm_hour=13, tm_min=9, tm_sec=59, tm_wday=6, tm_yday=12, tm_isdst=0), 0)

, но я также хотел бы, чтобы он возвращал:

"Soccer with @homies at Payne Whitney"

Есть ли способ сделать это с помощью parsedatetime или Требуется другой пакет Python?

PS

Я обещаю, что это имеет практическое применение, мы используем его для создания этого: magical.app

1 Ответ

1 голос
/ 14 января 2020

Единственный метод Calendar, который возвращает эту информацию, это nlp() (что, я полагаю, означает обработку естественного языка). Вот функция, возвращающая все части ввода:

import parsedatetime

calendar = parsedatetime.Calendar()

def parse(string, source_time = None):
    ret = []
    parsed_parts = calendar.nlp(string, source_time)
    if parsed_parts:
        last_stop = 0
        for part in parsed_parts:
            dt, status, start, stop, segment = part
            if start > last_stop:
                ret.append((None, 0, string[last_stop:start]))
            ret.append((dt, status, segment))
            last_stop = stop
        if len(string) > last_stop:
            ret.append((None, 0, string[last_stop:]))
    return ret

for s in ("Soccer with @homies at Payne Whitney tomorrow at 2 pm to 4 pm!",
          "Soccer with @homies at Payne Whitney tomorrow starting at 2 pm to 4 pm!",
          "Soccer with @homies at Payne Whitney tomorrow starting at 3 pm to 5 pm!"):
    print()
    print(s)
    result = parse(s)
    for part in result:
        print(part)

Вывод:

Soccer with @homies at Payne Whitney tomorrow at 2 pm to 4 pm!
(None, 0, 'Soccer with @homies at Payne Whitney ')
(datetime.datetime(2020, 1, 15, 16, 0), 3, 'tomorrow at 2 pm to 4 pm')
(None, 0, '!')

Soccer with @homies at Payne Whitney tomorrow starting at 2 pm to 4 pm!
(None, 0, 'Soccer with @homies at Payne Whitney ')
(datetime.datetime(2020, 1, 15, 9, 0), 1, 'tomorrow')
(None, 0, ' starting ')
(datetime.datetime(2020, 1, 14, 16, 0), 2, 'at 2 pm to 4 pm')
(None, 0, '!')

Soccer with @homies at Payne Whitney tomorrow starting at 3 pm to 5 pm!
(None, 0, 'Soccer with @homies at Payne Whitney ')
(datetime.datetime(2020, 1, 15, 9, 0), 1, 'tomorrow')
(None, 0, ' starting ')
(datetime.datetime(2020, 1, 14, 15, 0), 2, 'at 3 pm')
(None, 0, ' to ')
(datetime.datetime(2020, 1, 14, 17, 0), 2, '5 pm')
(None, 0, '!')

status сообщает вам, является ли связанный datetime фактической датой (1), время (2), дата / время (3) или нет (0). В первых двух случаях пропущенные поля берутся из source_time или из текущего времени, если это None.

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

Альтернативная библиотека - dateparser. Он выглядит мощнее, но имеет свои проблемы. Функция dateparser.parse.search_dates() приближается к тому, что вас интересует, но я не смог выяснить, как определить, передает ли обработанный datetime только информацию о дате, только информацию о времени или и то, и другое. В любом случае, вот функция, которая использует search_dates() для получения вывода, аналогичного приведенному выше, но без status каждой части:

from dateparser.search import search_dates

def parse(string: str):
    ret = []
    parsed_parts = search_dates(string)
    if parsed_parts:
        last_stop = 0
        for part in parsed_parts:
            segment, dt = part
            start = string.find(segment, last_stop)
            stop = start + len(segment)
            if start > last_stop:
                ret.append((None, string[last_stop:start]))
            ret.append((dt, segment))
            last_stop = stop
        if len(string) > last_stop:
            ret.append((None, string[last_stop:]))
    return ret


for s in ("Soccer with @homies at Payne Whitney tomorrow at 2 pm to 4 pm!",
          "Soccer with @homies at Payne Whitney tomorrow starting at 2 pm to 4 pm!",
          "Soccer with @homies at Payne Whitney tomorrow starting at 3 pm to 5 pm!"):
    print()
    print(s)
    result = parse(s)
    for part in result:
        print(part)

Вывод:

Soccer with @homies at Payne Whitney tomorrow at 2 pm to 4 pm!
(None, 'Soccer with @homies at Payne Whitney ')
(datetime.datetime(2020, 1, 15, 14, 0), 'tomorrow at 2 pm')
(None, ' to ')
(datetime.datetime(2020, 1, 13, 16, 0), '4 pm')
(None, '!')

Soccer with @homies at Payne Whitney tomorrow starting at 2 pm to 4 pm!
(None, 'Soccer with @homies at Payne Whitney ')
(datetime.datetime(2020, 1, 15, 0, 43, 0, 726130), 'tomorrow')
(None, ' starting ')
(datetime.datetime(2020, 1, 13, 14, 0), 'at 2 pm')
(None, ' to ')
(datetime.datetime(2020, 1, 13, 16, 0), '4 pm')
(None, '!')

Soccer with @homies at Payne Whitney tomorrow starting at 3 pm to 5 pm!
(None, 'Soccer with @homies at Payne Whitney ')
(datetime.datetime(2020, 1, 15, 0, 43, 0, 784468), 'tomorrow')
(None, ' starting ')
(datetime.datetime(2020, 1, 13, 15, 0), 'at 3 pm')
(None, ' to ')
(datetime.datetime(2020, 1, 13, 17, 0), '5 pm')
(None, '!')

Я думаю, что поиск подстроки во входных данных является приемлемым, и синтаксический анализ кажется более предсказуемым, но проблема не в том, как интерпретировать каждый datetime.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...