Регулярное выражение: выберите первое наиболее точное совпадение до конца - PullRequest
1 голос
/ 22 октября 2019

Цель : извлечь первое письмо из цепочки писем

Описание : Основываясь на ручной проверке писем, я понял, что следующее письмо впоток электронной почты всегда начинается с набора From, Sent, To и Subject

Тестовый ввод :

Hello World from: the other side of the first email

from: this
sent: at
to: that
subject: what

second email

from: this
sent: at
to: that
subject: what


third email

from: this
date: at
to: that
subject: what

fourth email

Ожидаемый вывод :

Hello World from: the other side of the first email

Неудачные попытки :

После перерывов при наличии from: в первом письме

(.*)((from:[\s\S]+?)(sent:[\s\S]+?)(to:[\s\S]+?)(subject:[\s\S]+))

Подписказавершается неудачно, когда есть повторяющиеся группы From, Sent, To и Subject

([\s\S]+)((from:(?:(?!from:)[\s\S])+?sent:(?:(?!sent:)[\s\S])+?to:(?:(?!to:)[\s\S])+?subject:(?:(?!subject:)[\s\S])+))

Вторая попытка работает с PCRE (PHP) , когда параметр ungreedy (флаг) выбран. Тем не менее, эта опция недоступна в Python, и я не мог найти способ заставить его работать.

Regex101 demo

Ответы [ 3 ]

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

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

^(.*)\r?\n\s*\r?\nfrom:.*\r?\nsent:.*\r?\nto:.*\r?\nsubject:
  • ^ Начало строки
  • (.*)Совпадение с любым символом, кроме новой строки 0+ раз
  • \r?\n\s* Сопоставление новой строки с последующим 0+ разом пробельного символа с использованием \s*
  • \r?\nfrom:.* Сопоставление следующей строки, начинающейся с from:
  • \r?\nsent:.* Соответствует следующей строке, начиная с sent:
  • \r?\nto:.* Соответствует следующей строке, начиная с to:
  • \r?\nsubject:.* Соответствует следующей строкеначиная с subject:

Обратите внимание, что в демонстрационной ссылке глобальный флаг g в правом верхнем углу не включен.

Regex demo | Python demo

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

^(.*(?:\r?\n(?!(?:from|sent|to|subject):).*)*)\r?\n\s*\r?\nfrom:.*\r?\nsent:.*\r?\nto:.*\r?\nsubject:

Regex demo

Если есть пробелы между from, sent, to и subject 0+ (*) могут быть сопоставлены пробельные символы

^(.*(?:\r?\n(?!(?:from|sent|to|subject):).*)*)\r?\s*\r?\sfrom:.*\r?\s*sent:.*\r?\s*to:.*\r?\s*subject:

Regex demo

0 голосов
/ 22 октября 2019
import re

text = """Hello World from: the other side of the first email

from: this
sent: at
to: that
subject: what

second email

from: this
sent: at
to: that
subject: what


third email

from: this
date: at
to: that
subject: what

fourth email"""

m = re.match(r'.*?(?=^from:[^\n]*\nsent:[^\n]*\nto:[^\n]*\nsubject:[^\n]*$)', text, re.MULTILINE | re.DOTALL)
print(m.group(0))

Отпечатки:

Hello World from: the other side of the first email
0 голосов
/ 22 октября 2019

Может быть, я неправильно понимаю, но почему бы вам просто не сделать это:

re.compile(r"^.*from:\s(\w+@\w+\.\w+)")

Эта строка найдет первую строку в «форме электронной почты» (группа 1) после первого «от:»в начале строки.

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