Ошибка Python re.sub() для многострочной строки

У меня есть часть сценария, которая выглядит примерно так:

import re, sys
print(sys.version) # so you can see my Python version

repl = (
    "use bravo\\api\\resources\\usersResource;\n"
    "use bravo\\api\\resources\\groupsResource;\n"
    "use bravo\\api\\resources\\bandsResource;\n"
    "use bravo\\api\\resources\\setlistsResource;\n"
    "use bravo\\api\\resources\\songsResource;"
)

pattern = r'\{\{\$use_table_resources\}\}'
string = "{{$use_table_resources}}"

re.sub(pattern, repl, string)

Всякий раз, когда я запускаю его, я получаю следующий вывод и ошибку:

3.6.2 |Anaconda, Inc.| (default, Sep 19 2017, 08:03:39) [MSC v.1900 64 bit (AMD64)]
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    re.sub(pattern, repl, string)
  File "C:\ProgramData\Anaconda3\lib\re.py", line 191, in sub
    return _compile(pattern, flags).sub(repl, string, count)
  File "C:\ProgramData\Anaconda3\lib\re.py", line 326, in _subx
    template = _compile_repl(template, pattern)
  File "C:\ProgramData\Anaconda3\lib\re.py", line 317, in _compile_repl
    return sre_parse.parse_template(repl, pattern)
  File "C:\ProgramData\Anaconda3\lib\sre_parse.py", line 904, in parse_template
    raise s.error("missing <")
sre_constants.error: missing < at position 64 (line 2, column 26)

Это работает иногда, когда я делаю repl замена строки короче, но я действительно не могу понять это. Насколько я могу сказать, я работаю в рамках их ограничений, в соответствии с API re.sub (...)

Я знаю, что этот простой случай не оправдывает использование регулярных выражений, но этот фрагмент кода взят из гораздо большей части программного обеспечения. Мне не нужны никакие ответы, говорящие мне, что регулярное выражение - неправильный подход, потому что это на самом деле самый простой случай, который я мог бы привести, который все еще воспроизводит проблему. Есть более сложные случаи, когда мне нужно, чтобы RegEx действительно выполнял свою работу.

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

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

1 ответ

Решение

В вашей замещающей строке недостаточно экранирования, поэтому обратный слеш интерпретируется механизмом регулярных выражений как начало захваченной группы (как в классическом r"\1" или же "\\1" без сырого префикса).

Вы можете добавить необработанный префикс перед каждой строкой, но я бы предпочел использовать многострочные необработанные строки, подобные этой (проще для чтения):

repl = r"""use bravo\\api\\resources\\usersResource;
use bravo\\api\\resources\\groupsResource;
use bravo\\api\\resources\\bandsResource;
use bravo\\api\\resources\\setlistsResource;
use bravo\\api\\resources\\songsResource;
"""

тогда полученная замена

use bravo\api\resources\usersResource;
use bravo\api\resources\groupsResource;
use bravo\api\resources\bandsResource;
use bravo\api\resources\setlistsResource;
use bravo\api\resources\songsResource;

Теперь без изменения ввода:

с помощью re.escape лайк re.sub(pattern, re.escape(repl), string) не работает так хорошо, потому что пробел и конец строки также экранированы

Но вы можете сделать это, поскольку знаете, что единственными проблемными символами являются обратные слеши:

re.sub(pattern, repl.replace("\\",r"\\"), string)

(он заменяет обратную косую черту двойной обратной косой чертой, и результат остается тем же)

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