Мне нужно обернуть строку MathJax тегом HTML. Интересно, как исключить \) из строки поиска, чтобы она не соответствовала полному тексту. С одним символом это легко, например, [^)], но что делать, когда мне нужно сделать то же самое с, например, два символа один за другим \)?

search_str = "\(\ce{\sigma_{s}^{b}(H2O)}\) bla bla \(\ce{\sigma_{s}^{b}(H2O)}\)"
out = re.sub(r'(\\\([^\\\)]+\\\))', '<span>\1</span>', search_str)
1
d3im 8 Дек 2016 в 17:23

3 ответа

Лучший ответ

Вы пытаетесь сопоставить любой текст, но \) 2-символьная подстрока, 2-символьная последовательность символов, с [^\\\)]+, что неверно, поскольку [^...] отмененный класс cahracter, который может соответствовать отдельному персонаж попадает в определенный диапазон или набор символов, определенных в классе. Он никогда не может совпадать с комбинациями символов, * или + квантификаторы просто повторяют совпадение с одним символом.

То, о чем вы думаете, называется закаленный жадный жетон, (?:(?!\\\)).)* или (?:(?!\\\)).)*?.

Однако закаленный жадный токен в этом случае не является наилучшей практикой. См. Примечание rexegg.com о том, когда не использовать TGT:

Для поставленной задачи этот метод не дает никаких преимуществ перед ленивой точкой-звездой .*?{END}. Хотя их логика отличается на каждом шаге перед сопоставлением символа, оба метода вынуждают движок посмотреть, что из этого следует: {END}.

Сравнительная производительность этих двух версий будет зависеть от внутренней оптимизации вашего движка. pcretest указывает, что для PCRE требуется намного меньше шагов для версии с отложенной точкой. , На моем ноутбуке, когда оба выражения выполняются миллион раз по строке {START} Mary {END}, pcretest требуется 400 миллисекунд на 10000 прогонов для отложенной версии и 800 миллисекунд для закаленной версии.

Поэтому, если строка, которая ограничивает точку, является разделителем, который мы собираемся сопоставить в конечном итоге (как в нашем примере с {END}), этот метод ничего не добавляет к ленивой точечной звезде, которая лучше оптимизирована для этой работы.

Ваши строки кажутся правильными и довольно короткими, используйте простой шаблон соответствия ленивых точек , то есть \\\(.*?\\\) регулярное выражение.

Кроме того, вам нужно использовать префикс r, необработанный строковый литерал, в определении шаблона замены, или \1 будет проанализирован как шестнадцатеричный символ (\x01, начало заголовка ) .

import re
search_str = r"\(\ce{\sigma_{s}^{b}(H2O)}\) bla bla \(\ce{\sigma_{s}^{b}(H2O)}\)"
print(search_str)
out = re.sub(r'(\\\(.*?\\\))', r'<span>\1</span>', search_str)
print(out)

Смотрите демонстрацию Python

0
Wiktor Stribiżew 24 Янв 2020 в 22:54

Я думаю, что [^\\][^)] должен добиться цели, или. почти так. Это будет соответствовать любым двум символам, если первый не является косой чертой, а второй не является закрывающим знаком. Вы также можете поэкспериментировать с некоторой группировкой, если это не совсем то, что вы хотите.

0
dcrosta 8 Дек 2016 в 14:26

Благодаря рекомендации Себастьяна я использовал Tempered Greedy Token:

(\\\((?:(?!\\\)).)*\\\)

Просто потрясающе :-)

0
d3im 9 Дек 2016 в 07:54