【问题标题】:Python re.sub() failure on multiline string多行字符串上的 Python re.sub() 失败
【发布时间】:2018-09-01 19:56:35
【问题描述】:

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

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

我知道这个简单的例子不能证明使用正则表达式是合理的,但是这个 sn-p 代码是从一个更大的软件中取出的。我不需要任何答案告诉我正则表达式是错误的方法,因为这实际上是我可以产生的最简单的情况,它仍然会重现问题。有 更复杂的实例,我需要 RegEx 来实际完成它的工作。

不管怎样,我认为问题出在替换字符串的内容上,听起来很奇怪。当我使用较短的替换字符串时,我不会遇到此错误。

非常感谢任何指针。这可能是一件非常小而愚蠢的事情,但我已经回来过几次了,我找不到它。

【问题讨论】:

    标签: python regex python-3.6 multiline


    【解决方案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.sub(pattern, re.escape(repl), string) 这样使用re.escape 效果不佳,因为空格和行尾也会被转义

    但是您可以这样做,因为您知道唯一有问题的字符是反斜杠:

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

    (它用双反斜杠替换反斜杠,输出相同)

    【讨论】:

    • 你知道逃避替换的简单方法吗?我的程序其余部分中的替换文本是从另一个文本源生成的。
    • 非常感谢,先生!我已经追这只兔子差不多一整天了
    • 不客气。我自己花了比预期更长的时间。该死的正则表达式:)
    猜你喜欢
    • 2016-02-26
    • 2016-08-09
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-12
    • 2015-11-08
    • 1970-01-01
    相关资源
    最近更新 更多