Разобрать заголовок электронной почты из текста, используя регулярное выражение PCRE

Мне нужно проанализировать (разделить) текстовый файл, содержащий электронные письма, экспортированные из Outlook. Я разделяю его, используя preg_split с PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE

Моя цель - захватить раздел заголовка сообщения с регулярным выражением, т.е. начиная со строки «От:» и заканчивая пустой строкой перед телом сообщения.

Ограничения:

  • Ожидаются многоязычные имена полей
  • Количество полей заголовка варьируется (CC, BCC, вложения)
  • Некоторые поля могут располагаться более чем в одной строке (Кому, Копия, Скрытая копия, Тема, Вложения)

текстовый файл предварительно обрабатывается: замените несколько пробелов и табуляции одним пробелом, замените начальные и конечные пробелы.

Я был на этом весь день, не могу заставить последнюю часть работать. Это работает на [странице тестирования регулярных выражений gskinner]: http://regexr.com?36v27, но не в php .

Предмет:

From: Black, Jack (LA)
Sent: Monday, October 28, 2013 6:36 PM
To: George, Jackson (London); DCS.CC.DARWIN (Australia)
Cc: Bar, Foo (Istanbul); Ex, Reg (Istanbul); Smith, John (Istanbul); Rambo,
John J. (Gaziantep); Matrix, John (Phuket)
Subject: RE: PREVENTIVE AND CORRECTIVE ACTIONS / FOOBAR

Dear George,

venenatis imperdiet quam. Proin a egestas nunc, et mattis elit. In hac habitasse platea dictumst. Nulla dolor nibh, tempus ut neque eu, tempus fermentum mauris. Mauris nec ipsum nec sapien commodo scelerisque ut eu urna. Pellentesque eu neque in enim adipiscing faucibus. Sed interdum arcu et sem mollis iaculis. Duis euismod laoreet ligula lacinia dapibus. Vestibulum ullamcorper malesuada metus at malesuada. 

 Nullam enim elit, auctor vehicula orci eget, imperdiet feugiat odio. Etiam dapibus sagittis sem a varius. Nulla sit amet convallis mi, sit amet rutrum ipsum. In libero lectus, mattis at dui eu.

Thank you and best regards,

Jack B. Black (Mr)
Operations Manager (GGD)
FU Supervisor (R34, R57)

Phone: +1112212212 (local 1111)
Mobile: +12 121.111.11.12

From: George, Jackson (UK)
Sent: Monday, October 28, 2013 5:57 PM
To: DCS.CC.DARWIN (Australia)
Bar, Foo (Istanbul); Ex, Reg (Istanbul); Smith, John (Istanbul); Rambo,
John J. (Gaziantep); Matrix, John (Phuket)
Subject: PREVENTIVE AND CORRECTIVE ACTIONS / FOOBAR

Dear Colleagues,

ermentum. Duis ipsum quam, bibendum a risus nec, tincidunt fringilla lectus. Nunc vel dictum massa, et cursus nunc. Mauris tincidunt felis eget justo congue volutpat. Nulla condimentum accumsan elementum. Integer commodo, lorem eu pharetra suscipit, ligula.

Best Regards.

SDFD srfgGD
Field coordinator (GGD)
Customer Representative

sds dfsd sdfgsef sdfsd
sgzdfgdfg fgfg gdfg
Footer text etc
sdfdfdf dfgsdfgsdfgsdfg
Phone : +90 212 368 40 00 (ext:3814)

Регулярное выражение:

preg_match(
                 '/                         # delimiter
                (                           # capturing group start
                [\ A-Z][a-z]+:.+\(.+\)\R    # From: field
                [A-Z][a-z]+:.+\R            # Sent: fields
                [A-Z][a-z]+:.+\R            # To: field (1st line)
                (?:.+\R)+              # any additional header lines, before blank line (To, CC, BCC, Subject, Attachments)
                )                           # capturing group end
                # delimiter + modifiers /x',$text_clean, $matches);
        echo '<b>Matches: '.count($matches).'</b>';
        print_r($matches);   

У меня проблема с получением дополнительных строк заголовка:

(?:.+\R)+              # any additional header lines...

Любая помощь приветствуется


person B-and-P    schedule 29.10.2013    source источник
comment
У меня отлично работает: ideone.com/Xj6aaF. Я использовал PHP-синтаксис heredoc для указания тестовой строки. Я предполагаю, что вы делаете что-то неправильно, указывая тестовую строку (или импортируя фактический текст электронной почты) в PHP. Опубликуйте эту часть, и, возможно, кто-нибудь сможет вам помочь!   -  person slackwing    schedule 29.10.2013
comment
Вы не можете поместить комментарий и конечный разделитель на той же строке после него.   -  person Casimir et Hippolyte    schedule 29.10.2013
comment
Если Outlook экспортирует заголовок Cc: таким образом, с незащищенным переносом строки в середине значения поля, вы в основном облажались.   -  person tripleee    schedule 29.10.2013
comment
@CasimiretHippolyte Судя по всему, можно - работает без ошибок   -  person B-and-P    schedule 30.10.2013


Ответы (2)


Самый короткий способ — использовать preg_match_all с ленивым квантификатором:

preg_match_all('/^From.*?\R\R/ims', $mails, $matches);
print_r($matches);
person Casimir et Hippolyte    schedule 29.10.2013
comment
Спасибо, но это не годится - оно также будет соответствовать From в середине сообщения до пустой строки. Я заявил, что ожидаются многоязычные имена полей, поэтому От может быть От, Да и т. д. любой язык, на который переводится Outlook (Windows?). - person B-and-P; 30.10.2013

Спасибо всем за вклад, однако я понял это, используя свой метод. Несколько моментов меня смущают, но рабочее решение ниже.

  1. Почему preg_match возвращает первый результат дважды вместо двух совпадений:(http://www.ideone.com/Xj6aaF )1

  2. (?:.+\R)+ Точка, кажется, соответствует любому символу И НИКАКИМ СИМВОЛАМ, поэтому она продолжала пропускать пустые строки. Я нахожу это странным — разве + не должно быть 1 or more quantifier?

Во всяком случае, когда я изменил свой шаблон регулярного выражения на (?:\S.+\R)+, он делает то, что я хочу, используя preg_split.

Демо

Хотя технически моя проблема решена, я бы хотел, чтобы кто-нибудь объяснил два вышеуказанных момента.

person B-and-P    schedule 30.10.2013