Многострочный разделитель регулярных выражений Python

Имея эту многострочную переменную:

raw = '''
CONTENT = ALL
TABLES = TEST.RAW_1
        , TEST.RAW_2
        , TEST.RAW_3
        , TEST.RAW_4
PARALLEL = 4
'''

Структура всегда TAG = CONTENT обе строки НЕ зафиксированы и CONTENT может содержать новые строки.

мне нужно regex получить:

[('CONTENT', 'ALL'), ('TABLES', 'TEST.RAW_1\n        , TEST.RAW_2\n        , TEST.RAW_3\n        , TEST.RAW_4\n'), ('PARALLEL', '4')]

Пробовал несколько комбинаций, но я не могу остановить regex двигатель в нужной точке для TABLES тег в качестве его содержимого представляет собой многострочную строку, разделенную следующим тегом.

Несколько попыток от переводчика:

>>> re.findall(r'(\w+?)\s=\s(.+?)', raw, re.DOTALL)
[('CONTENT', 'A'), ('TABLES', 'T'), ('PARALLEL', '4')]


>>> re.findall(r'^(\w+)\s=\s(.+)?', raw, re.M)
[('CONTENT', 'ALL'), ('TABLES', 'TEST.RAW_1'), ('PARALLEL', '4')]


>>> re.findall(r'(\w+)\s=\s(.+)?', raw, re.DOTALL)
[('CONTENT', 'ALL\nTABLES = TEST.RAW_1\n        , TEST.RAW_2\n        , TEST.RAW_3\n        , TEST.RAW_4\nPARALLEL = 4\n')]

Спасибо!

1 ответ

Решение

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

(\w+)\s=\s(.+?)(?=$|\n[A-Z])
                ^^^^^^^^^^^^

Для использования с модификатором DOTALL, чтобы . может соответствовать символу новой строки. (?=$|\n[A-Z]) предвидение потребует .+? совпадать до конца строки или до новой строки, за которой следует заглавная буква.

Смотрите демо-версию регулярного выражения.

И альтернатива, более быстрое регулярное выражение (поскольку это развернутая версия выражения выше) - но модификатор DOTALL НЕ должен использоваться с ним:

(\w+)\s*=\s*(.*(?:\n(?![A-Z]).*)*)

Смотрите еще одну демонстрацию регулярных выражений

Пояснение:

  • (\w+) - Группа 1 захватывает 1+ слов символов
  • \s*=\s* - а = символ, заключенный в необязательные (0+) пробелы
  • (.*(?:\n(?![A-Z]).*)*) - Группа 2 захватывает 0+ последовательностей:
    • .* - любые символы 0+, кроме новой строки
    • (?:\n(?![A-Z]).*)* - 0+ последовательностей:
      • \n(?![A-Z]) - символ перевода строки не сопровождается заглавной буквой ASCII
      • .* - любые символы 0+, кроме новой строки

Демо Python:

import re
p = re.compile(r'(\w+)\s=\s(.+?)(?=$|\n[A-Z])', re.DOTALL)
raw = '''
CONTENT = ALL
TABLES = TEST.RAW_1
        , TEST.RAW_2
        , TEST.RAW_3
        , TEST.RAW_4
PARALLEL = 4
'''
print(p.findall(raw))
Другие вопросы по тегам