如何扫描允许转义字符的字符串文字?

Mat*_*ias 5 python regex parsing escaping

我想解析一个输入字符串并确定它是否包含由双引号 ( ")包围的字符序列。字符序列本身不允许包含进一步的双引号,除非它们是由一个反斜线,像这样:\"

为了让事情变得更加复杂,反斜杠可以逃脱自己,像这样:\\\\"因此不会转义以两个(或任意偶数个)反斜杠 ( )开头的双引号。更糟糕的是,允许使用单个非转义反斜杠(即后跟 none"\)。

我试图用 Python 的re模块来解决这个问题。该模块文件告诉我们关于管道运营商A|B

扫描目标字符串时,'|'会从左到右尝试分隔 的 RE 。当一个模式完全匹配时,该分支被接受。这意味着一旦A匹配,B将不会被进一步测试,即使它会产生更长的整体匹配。换句话说,'|'运营商从不贪婪。

但是,这并不像我预期的那样工作:

>>> import re
>>> re.match(r'"(\\[\\"]|[^"])*"', r'"a\"')
<_sre.SRE_Match object; span=(0, 4), match='"a\\"'>
Run Code Online (Sandbox Code Playgroud)

这个正则表达式的想法是首先检查转义字符(\\\"),只有在没有找到的情况下,才检查任何没有找到的字符"(但它可能是单个\)。这可以发生任意次,并且必须用文字"字符包围。

我希望字符串"a\"根本不匹配,但显然确实如此。我希望\"匹配A零件和B未测试的零件,但显然是这样。

我真的不知道在这种情况下回溯是如何工作的,但是有没有办法避免它?

我想如果我"在单独的步骤中首先检查初始字符(并将其从输入中删除),它会起作用。然后我可以使用以下正则表达式来获取字符串的内容:

>>> re.match(r'(\\[\\"]|[^"])*', r'a\"')
<_sre.SRE_Match object; span=(0, 3), match='a\\"'>
Run Code Online (Sandbox Code Playgroud)

这将包括转义的报价。由于不会有结束语,我知道总的来说,给定的字符串不匹配。

我是否必须这样做,或者是否可以使用单个正则表达式而不需要额外的手动检查来解决这个问题?

在我的实际应用程序中,"-enclosed 字符串只是较大模式的一部分,因此我认为在单个正则表达式中一次完成所有操作会更简单。

我发现了类似的问题,但那些不认为单个非转义反斜杠可以成为字符串的一部分:regex to parse string with escape characters , Parsing for escape characters with a regular expression

Wik*_*żew 5

当使用"(\\[\\"]|[^"])*",则匹配"随后的0+序列\后接\",或非",然后接着是“关闭” "。请注意,当您的输入为 时"a\", 与\第二个替代分支匹配[^"](因为反斜杠是有效的非")。

您需要\从非中排除"

"(?:[^\\"]|\\.)*"
      ^^
Run Code Online (Sandbox Code Playgroud)

因此,我们匹配",然后是非"和非\(与[^\\"])或任何转义序列(与\\.),0 次或更多次。

然而,这个正则表达式不够有效,因为有很多回溯(由交替和量词引起)。展开的版本是:

"[^"\\]*(?:\\.[^"\\]*)*"
Run Code Online (Sandbox Code Playgroud)

查看正则表达式演示

最后一个模式匹配:

  • " - 双引号
  • [^"\\]*- 除\和之外的零个或多个字符"
  • (?:\\.[^"\\]*)* - 零个或多个序列
    • \\. - 反斜杠后跟除换行符以外的任何字符
    • [^"\\]*- 除\和之外的零个或多个字符"
  • " - 双引号

  • 答案是:回溯使 `[^"]` 有可能匹配 ``\`` 而不是 ``\"``。你的 `\\["\\]` 是第一个,并且在 `"a` 与 2 次 `[^"]` 匹配后,``\"`` 被第一个选择抓取。但是,最后一个 `"` 是*必须的*,这意味着正则表达式引擎将尝试重新组合迄今为止找到的捕获值以容纳 `"` 的某个位置。引擎回溯,并在 `"` 之前找到一个可以与第二个替代分支 `[^"]` 匹配的 `\``。请参阅 *regex debugger* 页面上的 [您的正则表达式](https://regex101.com/r/dZ4bB2/2),步骤 12、13。 (2认同)