Извлечение даты из строки в Python

82

Как я могу извлечь дату из строки типа «обезьяна 2010-07-10 любит банан»? Благодаря!

dmpop
источник
3
Просто подсказка: начинается и заканчивается цифрой. Дай мне подумать об этом. Хотя регулярное выражение может быть там вашим другом.
Hamish Grubijan

Ответы:

82

Если дата указана в фиксированной форме, вы можете просто использовать регулярное выражение для извлечения даты и «datetime.datetime.strptime» для анализа даты:

import re
from datetime import datetime

match = re.search(r'\d{4}-\d{2}-\d{2}', text)
date = datetime.strptime(match.group(), '%Y-%m-%d').date()

В противном случае, если дата указана в произвольной форме, вы не сможете легко ее извлечь.

лунный рог
источник
1
Что, если это будет в европейском формате, например, 20.01.1980, что означает «20 января 1980 года»? Что, если месяцы / дни / годы выходят за пределы разумного диапазона?
Hamish Grubijan
@lunaryorn В первом операторе относится ли "re" к строке, в которой мы ищем желаемый шаблон?
Вишал 05
@ vishal.k Это относится к встроенному в reмодуль, то есть import re.
lunaryorn 05
На случай, если кто-то другой совершил ту же ошибку: вам нужно from datetime import datetimeвместоimport datetime
dankal444
155

Используя python-dateutil :

In [1]: import dateutil.parser as dparser

In [18]: dparser.parse("monkey 2010-07-10 love banana",fuzzy=True)
Out[18]: datetime.datetime(2010, 7, 10, 0, 0)

Недействительные даты вызывают ValueError:

In [19]: dparser.parse("monkey 2010-07-32 love banana",fuzzy=True)
# ValueError: day is out of range for month

Он может распознавать даты во многих форматах:

In [20]: dparser.parse("monkey 20/01/1980 love banana",fuzzy=True)
Out[20]: datetime.datetime(1980, 1, 20, 0, 0)

Обратите внимание, что он делает предположение, если дата неоднозначна:

In [23]: dparser.parse("monkey 10/01/1980 love banana",fuzzy=True)
Out[23]: datetime.datetime(1980, 10, 1, 0, 0)

Но способ анализа неоднозначных дат можно настроить:

In [21]: dparser.parse("monkey 10/01/1980 love banana",fuzzy=True, dayfirst=True)
Out[21]: datetime.datetime(1980, 1, 10, 0, 0)
Unutbu
источник
3
@Hamish: если есть две даты (как в случае "monkey 10/01/1980 love 7/10/2010 banana"), это может вызвать ошибку ValueError или (как в случае "monkey 10/01/1980 love 2010-07-10 banana") оно может неверно истолковать вторую дату как обозначающую часы, минуты, секунды или часовой пояс. fuzzy=Trueдает ему право гадать.
unutbu
1
@unutbu str = "Автор flufie · 14 октября 2010 г., 23:22 · 26 ответов" Используя dateutil, я получаю "ValueError: час должен быть в 0..23"
saravanan
что будет, если в тексте более 1 даты?
alvas
1
@alvas: parseфункция может вызвать исключение (даже если fuzzy=True) или с fuzzy=True, она может вернуть первую дату или мешанину, состоящую из частей обеих дат. Так что на самом деле parseследует вызывать только строку, содержащую одну дату.
unutbu 09
1
@Kailegh: Да, можно было бы вывести индексы, используя fuzzy_with_tokens = True . Если вам нужны дополнительные пояснения, задайте новый вопрос.
unutbu 01
27

Для извлечения даты из строки в Python; лучший доступный модуль - это модуль поиска даты .

Вы можете использовать его в своем проекте Python, выполнив простые шаги, указанные ниже.

Шаг 1. Установите пакет datefinder

pip install datefinder

Шаг 2: используйте его в своем проекте

import datefinder

input_string = "monkey 2010-07-10 love banana"
# a generator will be returned by the datefinder module. I'm typecasting it to a list. Please read the note of caution provided at the bottom.
matches = list(datefinder.find_dates(input_string))

if len(matches) > 0:
    # date returned will be a datetime.datetime object. here we are only using the first match.
    date = matches[0]
    print date
else:
    print 'No dates found'

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

Финни Абрахам
источник
1
Я обнаружил, что datefinderпереданное неоднозначное сопоставление дат лучше, чем python-dateutilвозвращение только двух возможных дат из случайного сообщения в блоге medium.com вместо пяти. Однако не знаю, как он обрабатывает разные локации ...
CpILL
Это неплохо, но почему-то не работает, когда перед строкой даты стоит двоеточие (:): string = "Assessment Date: 17-May-2017 at 13:31" list(datefinder.find_dates(string.lower())) #[] string = "Assessment Date 17-May-2017 at 13:31" list(datefinder.find_dates(string.lower())) #[datetime.datetime(2017, 5, 17, 13, 31)]
Нарахари Б.М.
согласен с тем, что datefinder намного лучше, чем dateparser для неоднозначного текста
Джей Чон
2

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

Пользовательские шаблоны могут быть включены в ваше регулярное выражение в формате %{PATTERN_NAME}.

Вы также можете создать метку для этого шаблона, разделив двоеточием: %s{PATTERN_NAME:matched_string} . Если шаблон совпадает, значение будет возвращено как часть полученного словаря (например,result.get('matched_string') )

Например:

from pygrok import Grok

input_string = 'monkey 2010-07-10 love banana'
date_pattern = '%{YEAR:year}-%{MONTHNUM:month}-%{MONTHDAY:day}'

grok = Grok(date_pattern)
print(grok.match(input_string))

Полученное значение будет словарем:

{'month': '07', 'day': '10', 'year': '2010'}

Если шаблон date_pattern не существует в input_string, возвращаемое значение будет None. Напротив, если ваш шаблон не имеет меток, он вернет пустой словарь.{}

Рекомендации:

Обри Лавин
источник
Эта библиотека, то есть очень Python 2
Уолтер
1

Вы также можете попробовать модуль dateparser , который может быть медленнее, чем datefinder для произвольного текста, но который должен охватывать больше потенциальных случаев и форматов даты, а также значительное количество языков.

adbar
источник
-5

Если вам известно положение объекта даты в строке (например, в файле журнала), вы можете использовать .split () [index] для извлечения даты, не зная полностью ее формат.

Например:

>>> string = 'monkey 2010-07-10 love banana'
>>> date = string.split()[1]
>>> date
'2010-07-10'
dsod
источник