Python регулярное выражение, чтобы получить дату из разных комбинаций

1

У меня есть текстовый файл с несколькими строками, одна из которых содержит description поля, и это поле имеет несколько комбинаций или обозначений дат, окруженных другими строками, такими как colasas|04/18/2017|NXP, FTP Permanent|09|10|2012|FTP и Project|16 July 2005|Design. из которого я хочу только разобрать даты. Один из способов, который я нашел, - использовать модуль dateutil который выглядит сложным и много манипуляций для этой цели.

Поэтому, проходя тест примеров, он работает для определенных комбинаций.

>>> from dateutil.parser import parse
>>> test_cases = ['04/30/2009', '06/20/95', '8/2/69', '1/25/2011', '9/3/2002', '4-13-82', 'Mar-02-2009', 'Jan 20, 1974',
...               'March 20, 1990', 'Dec. 21, 2001', 'May 25 2009', '01 Mar 2002', '2 April 2003', '20 Aug. 2004',
...               '20 November, 1993', 'Aug 10th, 1994', 'Sept 1st, 2005', 'Feb. 22nd, 1988', 'Sept 2002', 'Sep 2002',
...               'December, 1998', 'Oct. 2000', '6/2008', '12/2001', '1998', '2002']
>>> for date_string in test_cases:
...     print(date_string, parse(date_string).strftime("%Y%m%d"))
...
04/30/2009 20090430
06/20/95 19950620
8/2/69 19690802
----- etc --------

Тем не менее, у меня есть следующая комбинация данных, которую мне нужно разобрать, но, выбирая решение выше, он не может получить результаты.

Поскольку description является необязательным, поскольку оно может отсутствовать в определенный момент, поэтому я рассмотрел использование (?:description:* (.*))? ,

description: colasas|04/18/2017|NXP
description: colasas|04/18/2017|NXP
description: Remedy Tkt 01212152 Orcad move
description: FTP Permanent|09|10|2012|FTP
description: Remedy Tkt 01212152 Orcad move
description: TDA Drop12 Account|July 2004|TDA Drop12 Account
description: ftp|121210|ftp
description: Design Foundry Project|16 July 2005|Design Foundry Project
description: FTP Permanent|10/10/2010|FTP
description: WFS-JP|7-31-05|WFS-JP
description: FTP Permanent|10|11|2010|FTP

Я повторно сформулировал вопрос. Просто позвольте больше видеть, чтобы получить больше ресурсов.

Ниже приведен сценарий actula, который имеет три разных совпадения dn, ftpuser и последнее description которое я ищу для решения. Ниже скрипт работает для всех совпадений, но последний feild, который представляет собой описание, имеющее смешанные и необработанные данные, из которых мне нужны только даты

и даты инкапсулируются между PIPES "|" ,

#!/usr/bin/python3
# ./dataparse.py
from __future__ import print_function
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL)
import re
with open('test2', 'r') as f:
    for line in f:
        line = line.strip()
        data = f.read()
        regex = (r"dn:(.*?)\nftpuser: (.*)\ndescription:* (.*)")
        matchObj = re.findall(regex, data)
        for index in matchObj:
            #print(index)
            index_str = ' '.join(index)
            new_str = re.sub(r'[=,]', ' ', index_str)
            new_str = new_str.split()
            print("{0:<30}{1:<20}{2:<50}".format(new_str[1],new_str[8],new_str[9]))

Результат:

$ ./dataparse.py
ab02                          disabled_5Mar07     Remedy
mela                          Y                   ROYALS|none|customer
ab01                          Y                   VGVzdGluZyA
[email protected]                   T                   REG-JP|7-31-05|REG-JP
  • 0
    Не используйте регулярные выражения. Просто используйте strptime с разными форматами времени, пока один из них не совпадет.
  • 0
    Возможно, вам потребуется реализовать экстрактор даты с настраиваемыми форматами в соответствии с ожидаемыми строками даты.
Показать ещё 2 комментария
Теги:

4 ответа

2

Используемый метод parse принимает аргумент ключевого слова, позволяющий игнорировать нерелевантные части строки.

:param fuzzy:
    Whether to allow fuzzy parsing, allowing for string like "Today is
    January 1, 2047 at 8:21:00AM".

Демо-версия:

>>> parse('colasas|04/18/2017|NXP', fuzzy=True)
datetime.datetime(2017, 4, 18, 0, 0)

Существует еще один, который также возвращает кортежи, включая части строки, которые были проигнорированы:

>>> parse('colasas|04/18/2017|NXP', fuzzy_with_tokens=True)
(datetime.datetime(2017, 4, 18, 0, 0), ('colasas|', '|NXP'))

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

1
text="""
description: colasas|04/18/2017|NXP
description: colasas|04/18/2017|NXP
description: Remedy Tkt 01212152 Orcad move
description: FTP Permanent|09|10|2012|FTP
description: Remedy Tkt 01212152 Orcad move
description: TDA Drop12 Account|July 2004|TDA Drop12 Account
description: ftp|121210|ftp
description: Design Foundry Project|16 July 2005|Design Foundry Project
description: FTP Permanent|10/10/2010|FTP
description: WFS-JP|7-31-05|WFS-JP
description: FTP Permanent|10|11|2010|FTP
"""
import re

reg=re.compile(r"(?ms)\|(\d\d)(\d\d)(\d\d)\||\|(\d{1,2})[\|/\-](\d{1,2})[\|/\-](\d{2,4})\||\|(\d*)\s*(\w+)\s*(\d{4})\|")

dates= [ t[:3] if t[1] else t[3:6] if t[4] else t[6:] for t in reg.findall(text) ]
print(dates)

"""
    regexp for |121210| ---> \|(\d\d)(\d\d)(\d\d)\|
    for |16 July 2005| ---> \|(\d*)\s*(\w+)\s*(\d{4})\|
    for the others ---> \|(\d{1,2})[\|/\-](\d{1,2})[\|/\-](\d{2,4})\|
"""
Output: [('04', '18', '2017'), ('04', '18', '2017'), ('09', '10', '2012'), ('', 'July', '2004'), ('12', '12', '10'), ('16', 'July', '2005'), ('10', '10', '2010'), ('7', '31', '05'), ('10', '11', '2010')]

Получите дату как есть:

reg=re.compile(r"(?ms)\|(\d{6})\||\|(\d{1,2}[\|/\-]\d{1,2}[\|/\-]\d{2,4})\||\|(\d*\s*\w+\s+\d{4})\|")

dates= [ t[0] or t[1] or t[2] for t in reg.findall(text) ]
print(dates)

Output:
['04/18/2017', '04/18/2017', '09|10|2012', 'July 2004', '121210', '16 July 2005', '10/10/2010', '7-31-05', '10|11|2010']
  • 0
    Kantal, спасибо, я попробую это.
  • 0
    Кантал, можем мы считать даты такими, какие они есть.
Показать ещё 1 комментарий
1

Использование некоторых строковых манипуляций

Демо - версия:

s = """description: colasas|04/18/2017|NXP
description: colasas|04/18/2017|NXP
description: Remedy Tkt 01212152 Orcad move
description: FTP Permanent|09|10|2012|FTP
description: Remedy Tkt 01212152 Orcad move
description: TDA Drop12 Account|July 2004|TDA Drop12 Account
description: ftp|121210|ftp
description: Design Foundry Project|16 July 2005|Design Foundry Project
description: FTP Permanent|10/10/2010|FTP
description: WFS-JP|7-31-05|WFS-JP
description: FTP Permanent|10|11|2010|FTP"""


from dateutil.parser import parse

for i in s.split("\n"):
    val = i.split("|", 1)                            #Split by first "|"
    if len(val) > 1:                                 #Check if Date in string.
        val = val[1].rpartition("|")[0]               #Split by right "|"
        print( parse(val, fuzzy=True) )

Выход:

2017-04-18 00:00:00
2017-04-18 00:00:00
2012-07-03 00:00:00
2004-07-03 00:00:00
2010-12-12 00:00:00
2005-07-16 00:00:00
2010-10-10 00:00:00
2005-07-31 00:00:00
2010-07-03 00:00:00

Что касается вашей ошибки datetime, удалите from datetime import datetime

Демо - версия:

import re
import datetime
strh = "description: colasas|04/18/2017|NXP"
match = re.search(r'\d{2}/\d{2}/\d{4}', strh)
date = datetime.datetime.strptime(match.group(), '%m/%d/%Y').date()
print(date)
  • 0
    все решение выглядит хорошо, однако я попросил регулярное выражение, потому что я использую это в сценарии , где он просматривает и другие данные ..
  • 0
    Ракеш, выглядит предложенный способ не дает правильные даты, посмотрите на третье вхождение
Показать ещё 2 комментария
0

Я достиг этого через regex учитывая значения между трубами следующим образом:

"(?:description:* .*\|([0-9]{1,2}[-/]+[0-9]{1,2}[-/]+[0-9]{2,4})\|.*)?"
  • 1
    это не соответствует 16 July 2005
  • 0
    @ Тото, ты прав.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню