1

Почему одно и то же регулярное выражение нормально отрабатывает на сайтах типа pythex.org но все время возвращает пустой список в ходе выполнения программы?

Строка которую пытаюсь парсить:

info = u'\nOutage start time:\r\n        3/23/2017 5:11:12 AM\n\nEstimated restoration time:\n\n\n\n\n\nEstimated customers impacted:\r\n1\n\nReason:\r\n        An object has made contact with power lines in your area. SRP crews are working to restore power as quickly as possible.\n\nImpacted area:\r\nS SCHNEPF RD to N QUAIL RUN LN and E JUDD RD to W MAGMA RD\n\n'

Регулярное выражение: (?<=start time:)(.*?)(?=Estimated)

Результат на сайте: 3/23/2017 5:11:12 AM введите сюда описание изображения

Результат в интерпретаторе (Python 2.7):

>>> re.findall(r'(?<=start time:)(.*?)(?=Estimated)', info, re.UNICODE)
[]
>>> re.findall(ur'(?<=start time:)(.*?)(?=Estimated)', info, re.UNICODE)
[]
jfs
  • 52,361
sky
  • 13

2 Answers2

1

Если вы работаете со строками Юникода, необходимо все строки преобразовывать в необходимый вид (либо объявляя строковый литералы с помощью префикса u, либо используя .decode / .encode).

Рабочий код с использованием вашей строки:

import re
info = u'\nOutage start time:\r\n        3/23/2017 5:11:12 AM\n\nEstimated restoration time:\n\n\n\n\n\nEstimated customers impacted:\r\n1\n\nReason:\r\n        An object has made contact with power lines in your area. SRP crews are working to restore power as quickly as possible.\n\nImpacted area:\r\nS SCHNEPF RD to N QUAIL RUN LN and E JUDD RD to W MAGMA RD\n\n'
print([x.encode('utf8') for x in re.findall(ur'start time:\s*(.*?)\s*Estimated', info)])
# => ['3/23/2017 5:11:12 AM']
  • так у меня строка с префиксом u, этого недостаточно? – sky Mar 24 '17 at 10:31
  • Нет, недостаточно. Кстати, не нужен модификатор re.UNICODE, так как в вашей регулярке нет предопределенных символьных классов \w, \d или даже границы слова \b (с помощью re.UNICODE эти операторы начинают распознавать соответствующие символы Юникода). – Wiktor Stribiżew Mar 24 '17 at 10:33
  • Ваш вариант работает, спасибо. – sky Mar 24 '17 at 10:35
  • Пожалуйста, если мой ответ помог вам решить проблему, отметьте ответ как решение (см. Что делать с ответами на мой вопрос?). – Wiktor Stribiżew Mar 24 '17 at 10:38
  • Скажите пожалуйста. я вижу Вы изменили регулярку - т.е начальный вариант все таки был неправильным? – sky Mar 24 '17 at 11:07
  • Нет, регулярку я не изменил. Просто исправил объявление входного литерала. – Wiktor Stribiżew Mar 24 '17 at 11:09
  • Используйте Unicode для работы с текстом. Печатайте Unicode напрямую. НЕ следует в байты текст превращать, используя жёстко прописанную кодировку (почему вы utf-8 выбрали? А если у человек на Винде в cmd запустить? Так кракозябры получаются – jfs Mar 25 '17 at 05:26
  • # -*- coding: utf-8 -*- в вышеприведенном коде необязателен, он и не главное. Если ТС не вводит строки от руки, пример с encode/decode очень даже кстати. – Wiktor Stribiżew Mar 25 '17 at 09:36
1

Не хватает re.DOTALL флага, так как ввод многострочный.

>>> re.findall(ur'(?<=start time:)(.*?)(?=Estimated)', info, re.UNICODE|re.DOTALL)
[u'\r\n        3/23/2017 5:11:12 AM\n\n']

Альтернативно, можно явно пробел указать в regex (если нас интересуют только даты, в которых нет перевода строки внутри):

>>> re.findall(ur'(?<=start time:)\s*(.*?)\s*(?=Estimated)', info, re.UNICODE)
[u'3/23/2017 5:11:12 AM']
jfs
  • 52,361
  • re.DOTALL тут не нужен, так как нужная информация находится на 1 строке. – Wiktor Stribiżew Mar 25 '17 at 08:00
  • @WiktorStribiżew неверно. Посмотрите на результат в первом примере: явно видно что он с "\r\n" начинается. В Питоне (и многих других языках) "\n" это символ новой строки. То есть "нужная информация" (дата) находится как минимум на второй строчке. – jfs Mar 25 '17 at 08:58
  • То, что информация на второй строчке, это не обсуждается. re.DOTALL изменяет поведение точки, а не то, на каких строчках находится совпадение. Т.к. данное отличие заявлено как основная причина проблемы, этот ответ неправилен. Кроме того, использование блоков просмотра вперед и назад в данном случае излишне, т.к. re.findall возвращает содержимое звхватывающих групп, если они определены в выражении (в данном случае, они есть). – Wiktor Stribiżew Mar 25 '17 at 09:33
  • @WiktorStribiżew прочтите хотя бы заголовок вопроса: re.DOTALL может объяснить почему одно и то же регулярное выражение работает в одном случае и не работает в другом. А так много вариантов может быть как сделать рабочее regex (пара вариантов приведена в ответе). – jfs Mar 25 '17 at 09:55