Регулярное выражение для самой длинной совпадающей последовательности между двумя строками - PullRequest
0 голосов
/ 20 ноября 2018

Я искал в Google свой вариант использования, но ничего полезного не нашел.

Я не специалист по регулярным выражениям, поэтому я был бы признателен, если бы кто-нибудь в сообществе мог помочь.

Вопрос:

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

Подстроки:

префиксы = ['Item 1', 'Item 1a', 'Item 1b']
суффиксы = ['Item 2', 'Item 2a', 'Item 2b']

Пример 1:

Item 1 ....
Item 2 ....
Item 1 ....
....
....
Item 2 ....
Item 1 ....
Элемент 2
Элемент 1a ....
....
....
....
....
Элемент 2b ....

Ожидаемый результат:

Элемент 1a ....
....
....
....
....

Почему этот результат?

Поскольку префикс Item 1a и суффикс Item 2bсоответствует самой длинной строке в тексте между ними из всех других пар префикс-суффикс.

Пример 2:

Элемент 1 ....
Элемент 2 ....
Элемент 1 ....
....
....
Элемент 2
.... Элемент 1 ....
Элемент 2
Элемент 1a .... ....
....
....
.... Item 2b
....

Ожидаемый результат:

Item 1 ....
....
....

Почему этот результат?

Это потому, что это самая большая строка между двумя строками (пара префиксов и суффиксов), где и префикс, и суффикс начинаются в начале строки.Обратите внимание, что есть другая пара (Item 1a - Item 2b), но так как Item 2b не идет в начале строки, мы не можем рассмотреть эту самую длинную последовательность.

Что я пробовал с регулярным выражением:

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

regexs = [r'^' + re.escape(pre) + '(.*?)' + re.escape(suf) for pre in prefixes for suf in suffixes]
for regex in regexs:
    re.findall(regex, text, re.MULTLINE)

Что я пытался использовать без регулярных выражений (функции строки Python):

def extract_longest_match(text, prefixes, suffixes):
    longest_match = ''
    for line in text.splitlines():
        if line.startswith(tuple(prefixes)):
            beg_index = text.index(line)
            for suf in suffixes:
                end_index = text.find(suf, beg_index+len(line))
                match = text[beg_index:end_index]
                if len(match) > len(longest_match ):
                    longest_match = match
    return longest_match 

Я что-то пропустил?

1 Ответ

0 голосов
/ 20 ноября 2018

Вам необходимо

Демо Python :

import re
s="""Item 1 ....
Item 2 ....
Item 1 ....
....
....
Item 2 ....
Item 1 ....
Item 2
Item 1a ....
....
....
....
....
Item 2b ...."""
prefixes = ['Item 1', 'Item 1a', 'Item 1b']
suffixes = ['Item 2', 'Item 2a', 'Item 2b']
rx = r"(?=^((?:{}).*?^(?:{})))".format("|".join(prefixes), "|".join(suffixes))
# Or, a version with word boundaries:
# rx = r"(?=^((?:{})\b.*?^(?:{})\b))".format("|".join(prefixes), "|".join(suffixes))
all_matches = re.findall(rx, s, re.S | re.M)
print(max(all_matches, key=len))

Вывод:

Item 1a ....
....
....
....
....
Item 2

Регулярное выражение выглядит как

(?sm)(?=^((?:Item 1|Item 1a|Item 1b).*?^(?:Item 2|Item 2a|Item 2b)))

С границами слов

(?sm)(?=^((?:Item 1|Item 1a|Item 1b)\b.*?^(?:Item 2|Item 2a|Item 2b)\b))

См. Демоверсию regex .

Подробности

  • (?sm) - re.S и re.M флаги
  • (?=^((?:Item 1|Item 1a|Item 1b).*?^(?:Item 2|Item 2a|Item 2b))) - положительный прогноз, совпадающий в любом месте, за которым сразу следует последовательность паттернов:
    • ^ - начало строки
    • ((?:Item 1|Item 1a|Item 1b).*?^(?:Item 2|Item 2a|Item 2b)) -Группа 1 (это значение возвращается с re.findall)
    • (?:Item 1|Item 1a|Item 1b) - любой из элементов чередования (возможно, имеет смысл добавить \b границы слова после ) здесь)
    • .*? - любые 0+ символов, как можно меньше
    • ^ - начало строки
    • (?:Item 2|Item 2a|Item 2b) - любая альтернатива из списка (возможно, этотакже имеет смысл добавить \b границы слова после ) здесь).
...