Регулярное выражение: сопоставить все символы между двумя строками - PullRequest
1 голос
/ 22 марта 2020

Пример: В Нидерландах арахисовое масло называют «pindakaas» (арахисовый сыр), а не «pindaboter» (арахисовое масло), поскольку слово «масло» предполагается использовать только с продуктами, которые содержат настоящее масло.

Я хочу сопоставить все между cheese и butter и наоборот.

Цели:

  • масло называется "пиндакаас" (арахисовый сыр)
  • сыр), а не "pindaboter" (арахисовое масло

РЕДАКТИРОВАТЬ: Используемый язык Python 3.7 и текущий reg-exp я использую cheese(.*?)butter.

Ответы [ 2 ]

3 голосов
/ 22 марта 2020

Проблема в вашем примере состоит в том, что последнее слово вашей первой цели - это первое слово вашей второй цели в исходной строке; «нормальный» синтаксис RegEx заставляет механизм RE потреблять совпадающие символы, т. е. эти символы недоступны для дальнейших совпадений.

Вы можете сделать это - в принципе - с помощью разновидностей Regex, таких как PCRE, используя группы захвата в lookahead утверждения, так как они не приводят к потреблению персонажа в утверждении. Но все это утверждение имеет свою цену в производительности. Матчи пройдут в двух группах захвата. Два примера:

Прямой подход:

/
\b(?=(.*?cheese))butter  # match butter, assert that cheese comes after it and capture
|                        # or
\b(?=(.*?butter))cheese  # match cheese, assert that butter comes after it and capture
/gsx                     # flags: global, single line, free spacing

Давайте посмотрим, как работает успешное совпадение \b(?=(.*?cheese))butter; тот же принцип отражен в другой альтернативе. Механизм регулярных выражений сначала ищет границу слова \b, то есть позицию в тексте, которая не имеет символа слова с обеих сторон. Найдя его, он попытается установить (?=(.*?cheese)) в этой позиции. На естественном языке: «Начиная здесь, найдите cheese как можно скорее. Только если вы найдете его, запишите всю строку, которую вы только что прошли в пронумерованной группе, и верните указатель совпадения туда, где мы начали. Затем разрешите сопоставление, чтобы продолжить «. Если утверждение было успешным, сопоставление продолжается и затем используется butter. У нас есть совпадение, указатель совпадения стоит за butter, и механизм регулярных выражений пытается выполнить то же самое (включая, конечно, альтернативу) в остальной части текста.

См. regex demo .

Несколько оптимизированная версия:

/
\b(?=((?:[^c]*+|c(?!heese))*cheese))butter
|
\b(?=((?:[^b]*+|b(?!utter))*butter))cheese
/gsx

См. regex demo .

Вывод:

Match 1
Full match  27-33   butter
Group 1.    27-70   butter is called "pindakaas" (peanut cheese

Match 2
Full match  64-70   cheese
Group 2.    64-111  cheese) rather than "pindaboter" (peanut butter

ИЛИ

Если каждый не против объединения совпадающей строки и захваченной строки для каждого совпадения после факта, это также будет работать и будет лучше с точки зрения производительности. (Вероятно, все еще не так хорошо, как решение overlap, увиденное в ответе Booboo.)

/\bbutter\b.*?\b(?=(cheese))|\bcheese\b.*?\b(?=(butter))/sg

Это соответствует каждому варианту только до границы слова перед вторым термином, что позволяет начать следующую попытку сопоставления с этим термином. Второй член не является частью строки соответствия, но хранится в захваченной группе: ['butter is called "pindakaas" (peanut ', 'cheese'], etc..

См. regex demo .

2 голосов
/ 23 марта 2020

Если вы устанавливаете пакет regex из репозитория PyPI, вы можете выполнить overlapped поиск:

import regex as re

text = 'In the Netherlands, peanut butter is called "pindakaas" (peanut cheese) rather than "pindaboter" (peanut butter) because the word butter is only supposed to be used with products that contain actual butter.'

l = re.findall(r'\bbutter\b.*?\bcheese\b|\bcheese\b.*?\bbutter\b', text, overlapped=True)
print(l)

Отпечатки:

['butter is called "pindakaas" (peanut cheese', 'cheese) rather than "pindaboter" (peanut butter']

Я использовал ваш basi c regex, но требуется, чтобы butter и cheese находились на границах слов, например \bbutter\b, помещая \b перед и после слов. Не стесняйтесь удалять или нет.

...