Как сопоставить вложенные макросы LaTeX с re в Python?

Я хотел правильно сопоставить макросы LaTeX, даже вложенные. См. следующее:

s = r'''
firstline
\lr{secondline\rl{ right-to-left
        \lr{nested left-to-right} end RTL }
        other text
}
\rl{ last \lr{end line 
} end RTL }
'''

Например, в приведенном выше примере я хочу сопоставить макрос \lr с его содержимым. Я пробовал следующее, но ни один из них не работал правильно:

re.findall(r'(?:\\lr\{.*\})', s, re.DOTALL)
['\\lr{secondline\\rl{ right-to-left\n        \\lr{nested left-to-right} end RTL }\n        other text\n}\n\\rl{ last \\lr{end line \n} end RTL }']

даже нежадный вариант в данном случае не сработал:

re.findall(r'(?:\\lr\{.*?\})', s, re.DOTALL)
['\\lr{secondline\\rl{ right-to-left\n        \\lr{nested left-to-right}',
 '\\lr{end line \n}']

Мне нужно какое-то регулярное выражение для правильного сопоставления, похожее на вложенные скобки, здесь у меня есть вложенные фигурные скобки для макросов LaTeX.

редактировать:

Я хотел бы получить следующие совпадения:

['\\lr{secondline\\rl{ right-to-left\n        \\lr{nested left-to-right} end RTL }\n        other text\n}', 
'\\lr{nested left-to-right}',
'\\lr{end line \n}']

Было бы идеально, если бы я знал об уровне вложенности, как показано ниже:

[('\\lr{secondline\\rl{ right-to-left\n        \\lr{nested left-to-right} end RTL }\n        other text\n}',1) 
('\\lr{nested left-to-right}',2)
('\\lr{end line \n}',1)]

Если можете pip install regex, то можете использовать этот код.

Wiktor Stribiżew 06.04.2022 19:46

@WiktorStribiżew Спасибо. Это замечательно. Как я могу получить все вложенные \lr?

javadr 06.04.2022 19:54

Пожалуйста, добавьте ожидаемый результат к вопросу.

Wiktor Stribiżew 06.04.2022 20:00

Пожалуйста, ознакомьтесь с новым изданием.

javadr 06.04.2022 20:06

Я сомневаюсь, что вы можете получить уровень вложенности с помощью регулярных выражений. Итак, все, что я могу предложить, это [x.group() for x in regex.finditer(r'\\lr(\{(?:[^{}]++|(?1))*})', s, overlapped=True)], см. демо.

Wiktor Stribiżew 06.04.2022 20:12

Отлично. Не могли бы вы опубликовать свой код в качестве ответа на мой вопрос?

javadr 06.04.2022 20:15

Разве нельзя сделать это с re?

javadr 06.04.2022 20:15

Нет, re многого не умеет.

Wiktor Stribiżew 06.04.2022 20:16

Очень ценю ваше время, чтобы решить мою проблему.

javadr 06.04.2022 20:17
Почему в 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
9
33
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

С модулем регулярного выражения PyPi (после его установки с помощью pip install regex) вы можете использовать

import regex

s = r'''
firstline
\lr{secondline\rl{ right-to-left
        \lr{nested left-to-right} end RTL }
        other text
}
\rl{ last \lr{end line 
} end RTL }
'''

print( [x.group() for x in regex.finditer(r'\\lr(\{(?:[^{}]++|(?1))*})', s, overlapped=True)] )
# => ['\\lr{secondline\\rl{ right-to-left\n        \\lr{nested left-to-right} end RTL }\n        other text\n}', '\\lr{nested left-to-right}', '\\lr{end line \n}']

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

Обратите также внимание на параметр overlapped=True, используемый с regex.finditer, который позволяет сопоставлять вложенные вхождения.

Подробности:

  • \\lr - \lr строка
  • (\{(?:[^{}]++|(?1))*}) - Группа 1 (определена для ссылки при рекурсии):
    • \{ - { символ
    • (?:[^{}]++|(?1))* - ноль или более повторений
    • [^{}]++ - один или несколько символов, отличных от { и }, без возможности повторного сопоставления текста в случае срабатывания поиска с возвратом (т.
    • | - или
    • (?1) - рекурсивный шаблон группы 1
    • } - символ }.

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