Удалить только начало предыдущего письма

Мне интересно, как удалить любой заголовок предыдущего сообщения в электронном письме. Есть пример сообщения:

Something above

-----Message d'origine-----
De : Myself <[email protected]>
Envoyé : vendredi 8 mars 2019 14:30
À : Someone <[email protected]>
Cc : AnotherGuy <[email protected]>
Objet : My bad I forgot how to do it

Hi,

blabla

И мне нужно удалить все между -----Message d'origine----- и carriage return и empty new line до "Hi,".

Я пробовал следующее регулярное выражение:

-----Message d'origine-----[\s\S]*?[\r\n]

Но только -----Message d'origine----- совпало без других строк ниже. Однако, если я использую вместо этого "Hi,", он соответствует всем строкам с ним:

-----Message d'origine-----[\s\S]*?Hi

Кто-нибудь может мне помочь, в чем проблема и как использовать вместо carriage return и empty new line?

Спасибо :)

Вы показали испробованное регулярное выражение, но не соответствующий код Python. Это важно: включили ли вы многострочное сопоставление регулярных выражений?

Konrad Rudolph 10.04.2019 12:02

Легкий. Сопоставьте две новые строки вместо одной: (?:\r?\n){2}. Это дубликат.

revo 10.04.2019 12:03

@revo Дубликат какие?

Konrad Rudolph 10.04.2019 12:05
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно сопоставить до первого появления разрыва строки двойной:

r"-----Message d'origine-----[\s\S]*?(?:\r?\n){2}"
                                     ^^^^^^^^^^^^

См. демонстрация регулярных выражений. Шаблон (?:\r?\n){2} соответствует двум повторениям окончаний строк CRLF или LF.

Пример кода Python:

import re
s = "YOUR STRING HERE"
s = re.sub(r"-----Message d'origine-----.*?(?:\r?\n){2}", '', s, flags=re.S)

Обратите внимание, что [\s\S] равно . в регулярном выражении, когда используется флаг re.S (=re.DOTALL).

Если вас беспокоит производительность, на которую влияет нежадный шаблон .*?, разверните его как

s = re.sub(r"-----Message d'origine-----.*(?:\r?\n(?!\r?\n).*)*\s*", "", s)

См. эта демонстрация регулярных выражений. Не используйте re.S / re.DOTALL с этим шаблоном!

[\s\S]*?(?:\r?\n){2} теперь .*(?:\r?\n(?!\r?\n).*)*:

  • .* - остаток строки
  • (?:\r?\n(?!\r?\n).*)* - 0 и более повторений
    • \r?\n(?!\r?\n) - за разрывом строки не следует другой разрыв строки
    • .* - остаток строки

Почему нежадный шаблон будет менее эффективным, чем ваш вариант? Я не знаю внутренностей механизма регулярных выражений Python, но по наивности они должны выполнять примерно ту же работу.

Konrad Rudolph 10.04.2019 12:12

@KonradRudolph Проверьте количество шагов для обоих регулярных выражений в regex101: 582/72. Разница связана с возвратом с помощью шаблона .*?, поскольку шаблон расширяется каждый раз, когда последующие шаблоны не совпадают. .* захватывает все символы до разрыва строки, и здесь меньше возвратов, поскольку проверка выполняется после того, как найден конец строки, нет необходимости расширять какой-либо шаблон char за char.

Wiktor Stribiżew 10.04.2019 12:16

Хм, это кажется мне ошибкой производительности в реализации: конечно, нежадное совпадение может быть реализовано таким же образом?

Konrad Rudolph 10.04.2019 12:18

@KonradRudolph Это ожидаемое поведение, а не ошибка. См. Могу ли я еще больше улучшить производительность этого регулярного выражения? для конкретного примера соответствия .* и .*?. При работе с длинными текстами не стоит полагаться на .*? или .*, если вы не уверены в позициях соответствия. Тогда следует использовать метод Развернуть петлю или вообще отказаться от регулярного выражения в пользу какого-либо метода синтаксического анализа.

Wiktor Stribiżew 10.04.2019 12:20

Точно, я запутался. Я неправильно понял вас, поскольку вы сказали, что .*?сам откатывается, а не следующий (?:\r?\n){2} (который сопоставляется на каждом шаге и обычно терпит неудачу). Я также пропустил, что ваш второй пример не работает в однострочном режиме, поэтому . просто соответствует меньше и это, поэтому он более эффективен, чем нежадный случай.

Konrad Rudolph 10.04.2019 12:30

Отлично, @WiktorStribiżew, спасибо за все советы, которые вы дали :) Я был довольно близок, но я не знал здесь концепции флагов и того, как здесь улучшить производительность.

toshiro92 10.04.2019 13:43

Другие вопросы по теме