Поиск дат в формате «24 апреля» или «18 декабря» с использованием регулярных выражений - PullRequest
0 голосов
/ 11 апреля 2019

Я должен найти все даты из текстового документа.Даты в формате «24 апреля» или «18 декабря».Я написал код, который делает эту работу, но вывод получается грязным.

Я попытался объединить два регулярных выражения с "|"оператор, но затем я получаю много пробелов в выводе.

d1 = "(January|February|March|April|May|June|July|August|September|October|November|December)\s+([0-9]{1,2})(st|nd|rd|th)"

d2 = "([0-9]{1,2})(st|nd|rd|th)\s+(of)\s+(January|February|March|April|May|June|July|August|September|October|November|December)"

e1 = re.compile(d1)
e2 = re.compile(d2)

dat1 = re.findall(e1, text)
dat2 = re.findall(e2, text)

print("\nList of dates in collection are : " + str(dat1) + str(dat2))

Фактический результат:

[('January', '6', 'th'), ('January', '2', 'nd')][('4', 'th', 'of', 'March')]

Ожидаемый результат:

[('January 6th'), ('January 2nd'), ('4th of March')]

Ответы [ 4 ]

1 голос
/ 11 апреля 2019

Возможно попробуйте это:

>>> import re

>>> string = '''On 24th of April, 1492 Columbus sailed the Ocean Blue
Setting the stage for imperial conquest where the first native was slain on December 18th
This system would continue until April 1st, 2019 when Arijit Jha thought of posting on S.O.
And finally delivered his message on the 11th of April'''



>>> re.findall('(?i)([\d]{1,2}[a-z]{2}[\s\w]{4,5}(?:Jan|Febr|March|April|May|June|July|August|Septem|Octo|Novem|Decem(?:uary|ber)*)|(?:Jan|Febr|March|April|May|June|July|August|Septem|Octo|Novem|Decem(?:uary|ber)*)[\s]{1,2}[\d]{1,2}[a-z]{2})', string)



#OUTPUT
['24th of April', 'December 18th', 'April 1st', '11th of April']

.

.

Вы также можете попробовать ниже, но это также будет соответствовать месяцу, независимо от каких-либо дат вокруг, которые вы не могли бы

>>> re.findall('(?i)((?:[\d]{1,2}[a-z]{2}[\ \w]{4,5})*(?:Jan|Febr|March|April|May|June|July|August|Septem|Octo|Novem|Decem(?:uary|ber)*)(?:[\ ]{1,2}[\d]{1,2}[a-z]{2}(?=\s|$|\W))*)', string)
1 голос
/ 11 апреля 2019

Если вы не знали, возможно, посмотрите на встроенную функцию datetime.strptime и библиотеку Arrow в первую очередь.

Несмотря на то, что регулярное выражение произвело на вас сильное впечатлениев ответе от FailSafe мой подход такой:

p = dict(
  day='[0-9]{1,2}',
  month='January|February|March|April|May|June|July|August|September|October|November|December',
  suffix='nd|rd|st|th'
)
a = lambda m: '{month} {day}{suffix}'.format(**m.groupdict())

d1 = '(?P<month>{month})\s+(?P<day>{day})(?P<suffix>{suffix})'.format(**p)
d2 = '(?P<day>{day})(?P<suffix>{suffix})\s+of\s+(?P<month>{month})'.format(**p)

a(re.search(d1, 'January 6th')) # 'January 6th'
a(re.search(d2, '6th of January')) # 'January 6th'

Используется функция именованных групп в Python regexes и приятные функции dict в сочетании с форматирование строки .

Для дальнейшего развития (упрощение регулярных выражений d [12]):

p2 = {k: '(?P<{}>{})'.format(k, v) for k, v in p.items()}
d1 = '{month}\s+{day}{suffix}'.format(**p2)
d2 = '{day}{suffix}\s+of\s+{month}'.format(**p2)
0 голосов
/ 12 апреля 2019

На ваш вопрос уже есть несколько ответов, поэтому я решил добавить еще один.Я недавно ответил на другой вопрос для аналогичной проблемы.Я расширил код этого ответа, чтобы поддержать ваш вопрос.Да, это долго, но код охватывает несколько форматов данных.Вы можете расширить его по мере необходимости или свернуть некоторые регулярные выражения в соответствии с вашими потребностями.

string_with_dates = '''On December 18th there will be an initial meeting for the codeathon that is scheduled for the 24th of April.  
Our second meeting will be on Jan 31, 2019, the third on 28th Feb and the fourth on the 4 March.'''


def find_dates(input):
  '''
  This function is used to extract date strings from provide text.

  Symbol references:
  YYYY = four-digit year
  MM = two-digit month (01=January, etc.)
  DD = two-digit day of month (01 through 31)
  hh = two digits of hour (00 through 23) (am/pm NOT allowed)
  mm = two digits of minute (00 through 59)
  ss = two digits of second (00 through 59)
   s = one or more digits representing a decimal fraction of a second
  TZD = time zone designator (Z or +hh:mm or -hh:mm)

 :param input: text
 :return: date string

 '''

 date_formats = [
            # Matches date format MM/DD/YYYY
            '(\d{2}\/\d{2}\/\d{4})',

            # Matches date format MM-DD-YYYY
            '(\d{2}-\d{2}-\d{4})',

            # Matches date format YYYY/MM/DD
            '(\d{4}\/\d{1,2}\/\d{1,2})',

            # Matches ISO 8601 format (YYYY-MM-DD)
            '(\d{4}-\d{1,2}-\d{1,2})',

            # Matches ISO 8601 format YYYYMMDD
            '(\d{4}\d{2}\d{2})',

            # Matches full_month_name dd, YYYY or full_month_name dd[suffixes], YYYY
            '(January|February|March|April|May|June|July|August|September|October|November|December)(\s\d{1,2}\W\s\d{4}|\s\d(st|nd|rd|th)\W\s\d{4})',

            # Matches full_month_name and dd[suffixes]
            '(January|February|March|April|May|June|July|August|September|October|November|December)\s\d{1,2}(st|nd|rd|th)',

            # Matches dd full_month_name
            '\d{1,2}\s(January|February|March|April|May|June|July|August|September|October|November|December)',

            # Matches dd[suffixes] of full_month_name, YYYY
            '\d{1,2}(st|nd|rd|th)\sof\s(January|February|March|April|May|June|July|August|September|October|November|December),\s\d{4}',

            # Matches dd[suffixes] of full_month_name
            '\d{1,2}(st|nd|rd|th)\sof\s(January|February|March|April|May|June|July|August|September|October|November|December)',

            # Matches dd abbreviated_month_name
            '\d{1,2}\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sept|Oct|Nov|Dec)',

            # Matches dd[suffixes] abbreviated_month_name
            '\d{1,2}(st|nd|rd|th)\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sept|Oct|Nov|Dec)',

            # Matches abbreviated_month_name dd, YYYY or abbreviated_month_name dd[suffixes], YYYY
            '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sept|Oct|Nov|Dec)(\s\d{1,2}\W\s\d{4}|\s\d(st|nd|rd|th)\W\s\d{4})',

            # Matches abbreviated_month_name and dd[suffixes]
            '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sept|Oct|Nov|Dec)\s\d{1,2}(st|nd|rd|th)',

            # Matches ISO 8601 format with time and time zone
            # yyyy-mm-ddThh:mm:ss.nnnnnn+|-hh:mm
            '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\+|-)\d{2}:\d{2}',

            # Matches ISO 8601 format Datetime with timezone
            # yyyymmddThhmmssZ
            '\d{8}T\d{6}Z',

            # Matches ISO 8601 format Datetime with timezone
            # yyyymmddThhmmss+|-hhmm
            '\d{8}T\d{6}(\+|-)\d{4}'
            ]

for item in date_formats:
  date_format = re.compile(r'\b{}\b'.format(item), re.IGNORECASE|re.MULTILINE)
  find_date = re.search(date_format, input)
  if find_date:
    print (find_date.group(0))
    # outputs 
    December 18th
    4 March
    24th of April
    28th Feb
    Jan 31, 2019

find_dates(string_with_dates)
0 голосов
/ 11 апреля 2019

Вы используете группы: (opt1|opt2|opt3),
, и вы не хотите, чтобы они «ловили» разные результаты.

Затем следует использовать группы без захвата: (?:opt1|opt2|opt3),
, например:
(?:January|February|March|April|May|June|July|August|September|October|November|December)

cf: Что такое группа без захвата?Что делает (? :)?

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