多行字符串上的Python re.sub()失败

时间:2018-09-01 19:56:35

标签: python regex python-3.6 multiline

我有一部分脚本看起来像这样……

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替换字符串时,这种方法可以工作,但我真的不知道。据re.sub(...) API

,据我所知,我正在他们的约束范围内工作

我知道,这种简单的情况并不能证明使用正则表达式是合理的,但是这段代码片段是从更大的软件中提取出来的。我不需要任何答案就可以告诉我正则表达式是错误的方法,因为实际上这是我可以产生的最简单的情况,但仍然可以重现问题。在 更为复杂的实例中,我需要RegEx才能真正完成其工作。

无论哪种方式,我都认为问题出在替换字符串的内容中,听起来很奇怪。当我使用较短的替换字符串时,不会遇到此错误。

非常感谢任何指针。这可能确实很小而且很愚蠢,但是我已经回过几次了,但是我找不到它。

1 个答案:

答案 0 :(得分:1)

替换字符串中没有足够的转义符,因此正则表达式引擎将反斜杠解释为捕获组的开始(例如不带原始前缀的经典r"\1""\\1")。

您可以在每个字符串之前添加原始前缀,但我宁愿使用这样的多行 raw 字符串(更易于阅读):

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)

(它将反斜杠替换为双反斜杠,并且输出相同)