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

时间:2016-05-22 18:41:05

标签: python regex parsing escaping

我想解析输入字符串并确定它是否包含由双引号(")包围的字符序列。 字符序列本身不允许包含其他双引号,除非它们通过反斜杠进行转义,如下所示:\"

为了使事情变得更复杂,反斜杠可以自行转义,如下所示:\\。因此,前两个(或任意偶数)反斜杠(\\")的双引号不会被转义。 更糟糕的是,允许单个非转义反斜杠(即"\之后)。

我正在尝试使用Python的re模块来解决这个问题。 module documentation告诉我们管道运算符A|B

  

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

然而,这并不像我预期的那样有效:

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

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

我希望字符串"a\"根本不匹配,但显然确实如此。 我希望\"匹配A部分和B部分不进行测试,但显然是。

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

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

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

这将包括转义报价。由于没有剩下的结束语,我知道整体而言,给定的字符串不匹配。

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

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

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

1 个答案:

答案 0 :(得分:3)

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

您需要从非[^"]

中排除"
\

因此,我们匹配",然后匹配非"(?:[^\\"]|\\.)*" ^^ 和非 - "(带")或任何转义序列(\) ,0次或更多次。

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

[^\\"]

请参阅regex demo

最后一个模式匹配:

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