2015-10-28 4 views
0

Я новичок в Python, но мне нужно сделать регулярное выражение, чтобы выбрать даты в формате dd-mm-yyyy. Я написал примерно так:Python regex date

format1 = re.findall('[0-2][0-9]-02-(\d){4}|(([0-2][0-9]|30)-(04|06|09|11)-(\d){4})|(([0-2][0-9]|30|31)-(01|03|05|07|08|10|12)-(\d){4})',article) 

Он также проверяет правильность формата даты. Я проверил, работает ли он на pythex.org I возвращает правильные даты, но, к сожалению, также несколько пустых матчей и случайных чисел:

Match 1 
1. None 
2. None 
3. None 
4. None 
5. None 
6. 21-10-2005 
7. 21 
8. 10 
9. 5 

Match 2 
1. None 
2. None 
3. None 
4. None 
5. None 
6. 31-12-1993 
7. 31 
8. 12 
9. 3 

Как я могу улучшить регулярное выражение, чтобы вернуться только даты или все, что ни капли Дата?

+0

Я немного запутался. Каково именно возвращение, которое вы ищете? Например, если article = '10 -10-1010 'и вы передаете его на python, вы получите >>> [(' ',' ',' ',' ',' ', '10 -10- 1991 ',' 10 ',' 10 ',' 1 ')] Вы просто хотите вернуть его '10 -10-1010'? Правда? Ложь? – Dval

+0

всего 10-10-1010 'было бы хорошо – Rabbit

ответ

3

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

Вот вещь: в регулярном выражении, ничего внутри скобок () является захвачена группой - она ​​выходит в качестве одного из элементов, захваченных в матче.

Если вы хотите использовать скобки для группы части рисунка (например, так, что вы можете использовать | на что-то ниже, чем верхний уровень), но вы не хотите текста внутри этой группы вводной быть отдельный элемент в матчевом выводе, тогда вы хотите использовать группу , не захватывающую.

Чтобы сделать это, где у вас было бы (foo), вместо этого используйте (?:foo) - добавив ?: в начало. Это предотвращает захват текста группой в финальном матче.

1

Предложение Амбера прекрасно. Но могу ли я сделать предложение? Попытайтесь не всунуть всю логику в само регулярное выражение. Это делает его почти нечитаемым и по-прежнему не обрабатывает угловые случаи, как написано (например, он принимает 29 февраля каждый год, а не только високосные годы). Не используйте регулярные выражения для работы с истинным парсером.

Вместо этого найдите общий вид, затем проанализируйте его с помощью выделенного кода синтаксического анализа даты, и если он пройдет синтаксический анализ, сохраните его. Например:

import datetime, re 

def is_valid_dmy_date(datestr): 
    try: 
     datetime.datetime.strptime(datestr, '%d-%m-%Y') 
    except ValueError: 
     return False 
    return True 

# In Python 3, wrap filter call in list() if you need a real list, 
# or just iterate results of filter directly if that's all you need 
all_dates = filter(is_valid_dmy_date, re.findall(r'\b\d\d-\d\d-\d{4}\b', article)) 

Вы обратите внимание, что регулярное выражение значительно упрощается (я добавил \b нулевой ширины утверждения, поэтому он не будет соответствовать что-то вроде 001-01-200123, но вы можете удалить их, если соответствующие даты должны иметь место даже без слов границы). Работа передается datetime.strptime, который знает, что даты на самом деле, так что правильно отвергает такие вещи, как 29 февраля 2011 года

1

re.findall возвращает кортеж, который содержит все результаты () захватывает. У вас есть 9 () в вашем обычном шаблоне, поэтому вы получили кортеж с 9 элементами. попробовать print format1[0][5] может решить проблему в этом случае или использовать re.search вместо
format1 = re.search('[0-2][0-9]-02-(\d){4}|(([0-2][0-9]|30)-(04|06|09|11)-(\d){4})|(([0-2][0-9]|30|31)-(01|03|05|07|08|10|12)-(\d){4})',article) print format1.group(0)