Python регулярное выражение, заменяющее весь матч, а не группу - PullRequest
0 голосов
/ 23 апреля 2020

Я создал регулярное выражение для соответствия блоку в файле конфигурации Apache. В редакторе регулярных выражений он показывает, что он правильно соответствует блоку и захватывает группу. Когда я пытаюсь заменить группу в Python, она заменяет все совпадение, а не группу.

#!/usr/bin/python
import re

pattern = r"^(?:<Directory\s*\"\/var\/www\/html\">).*?(?:AllowOverride\s*)(None).*?(?:<\/Directory>)$"
repl = r"\g<1>All"

with open('httpd.conf', 'r') as io:
    string = io.read()
    o = re.sub(pattern, repl, string, count=1, flags=re.M|re.S)
    print(o)

Вывод:

# Further relax access to the default document root:
NoneAll

Ожидается:

# Further relax access to the default document root:
<Directory "/var/www/html">
...
    AllowOverride None
...
</Directory>

Ответы [ 2 ]

2 голосов
/ 23 апреля 2020

Поскольку re.sub() работает, как спроектировано и задокументировано: https://docs.python.org/3.7/library/re.html#re .sub . В частности,

Возвращает строку, полученную путем замены крайнего левого не перекрывающегося вхождения шаблона в строке заменой repl.

То есть предполагается для замены всего матча. re.sub() не заботится о группах внутри вашего шаблона. Он просто заботится обо всем шаблоне (ie. Всего совпадения).

Вы можете достичь sh той же цели, передав заменяющую функцию . Это работает для меня:

#!/usr/bin/python3
import re

pattern = r"^<Directory\s*\"\/var\/www\/html\">.*?</Directory>"
def repl(match):
    # A fancier version of this would do a regex replacement, but
    # regex replacement inside a regex replacement makes my
    # brain hurt.
    text = match.group(0)
    text = text.replace("AllowOverride None", "AllowOverride All")
    return text

with open('httpd.conf', 'r') as io:
    string = io.read()
    o = re.sub(pattern, repl, string, count=0, flags=re.MULTILINE | re.DOTALL)
    print(o)

Ограничения:

  • предполагает, что <Directory> разделы не могут быть вложенными
  • это не очень гибко в отношении текста, это замена
1 голос
/ 23 апреля 2020

Как сказал Грег, проблема заключалась в фундаментальном неправильном понимании функции замены с моей стороны.

"То есть она должна заменить все совпадение. Re.sub () не заботится о группах внутри ваш шаблон. Он просто заботится обо всем шаблоне (ie. все совпадение). "

Я закончил тем, что изменил свое регулярное выражение на: ^(<Directory\s*\"\/var\/www\/html\">.*?AllowOverride\s*)(None)(.*?<\/Directory>)$

и выполнил замену как итак:

#!/usr/bin/python
import re

pattern = r"^(<Directory\s*\"\/var\/www\/html\">.*?AllowOverride\s*)(None)(.*?<\/Directory>)$"
repl = r"\g<1>All\g<3>"

with open('httpd.conf', 'r') as io:
    string = io.read()
    o = re.sub(pattern, repl, string, count=1, flags=re.M|re.S)
    print(o)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...