Сопоставление любого символа и / или неопределенных символов новой строки с регулярным выражением в python - PullRequest
2 голосов
/ 24 октября 2019

Я должен проанализировать текстовый файл журнала с регулярным выражением в Python. Это пример текста (с именем file):

20/01/18, 08:11 - Питер: Доброе утро

Как дела?

Питер 20/01/18, 09:00 - Кэролайн: все хорошо, спасибо. Вы?

20/01/18, 09:01 - Питер: Хорошо

У меня были некоторые проблемы несколько дней назад.

Теперь я счастлив

Вы работаете?

20/01/18, 09:02 - Кэролайн: Нет, я должна идти в супермаркет, чтобы купить овощи

20/01/18, 09:12 -Питер: Отлично!

Где ты сейчас?

Я попытался проанализировать весь текст с помощью этого регулярного выражения:

f = open(file, 'r', encoding='utf-8')
texts=re.findall('(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)',f.read())
f.close()

df= pd.DataFrame(texts,columns=['data','name','text'])

Однако у меня проблемыпри сопоставлении одного или нескольких символов новой строки в python (например, текст Питера в 09:01). Я также пытаюсь поработать с https://regex101.com/, чтобы найти возможное решение, но мне это не удалось.

Не могли бы вы мне помочь, пожалуйста?

Ответы [ 2 ]

2 голосов
/ 24 октября 2019

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

(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*(?:\r?\n(?!\d+/\d+/\d).*)*)

О последней части (.*(?:\r?\n(?!\d+/\d+/\d).*)*)

  • ( Группа захвата 3
    • .* Совпадение 0+ раз с любым символом, кроме новой строки
    • (?: Группа без захвата
      • \r?\n Соответствует новой строке
      • (?!\d+/\d+/\d).* Утверждение того, что справа, не соответствует формату даты
    • )* Закрыть группу без захвата и повторить 0+ раз
  • ) Закрыть группу

Regex demo

0 голосов
/ 24 октября 2019

По умолчанию . не будет соответствовать новой строке. Вам нужно использовать режим DOTALL , чтобы он соответствовал символам новой строки:

re.findall('(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)', f.read(), re.DOTALL)

Работает:

>>> import re
>>> s="""
... 20/01/18, 09:01 - Peter: Good
... 
... I had some problems few days ago.
... 
... Now I am happy
... 
... Are you working?"""
>>> re.findall('(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)', s, re.DOTALL)
[('20/01/18, 09:01', 'Peter', 'Good\n\nI had some problems few days ago.\n\nNow I am happy\n\nAre you working?')]
>>> _

Это не решает проблему соответствия всего остальноготекста!

См. ответ @ the четвертой птицы для реального решения.

Другое. Более явный способ справиться с этим - читать файл построчно и проверять, является ли строка продолжением.

rx = re.compile('^(\d+/\d+/\d+, \d+:\d+\d+) - (.+?): (.*)$') # Note the ^.
texts = []
for line in input_file:  # Files iterate line by line.
  new_match = rx.match(line)
  if new_match:
    texts.append(list(new_match.groups()))  # We want a list
  else:
    # We have a continuation line; append it to the last item of group.
    last = texts[-1]
    last[-1] += line  # Update in-place.

Об этом может быть проще подумать.

...