如何在 Python 后向断言正则表达式 (?<=\\) 中使用“\”来匹配类似 C++ 的引用字符串

How to use '\' in Python lookbehind assertion regex (?<=\\) to match C++-like quoted strings

如何使用后向断言在 Python 中匹配 r'\a'
实际上,我需要匹配 C++ 字符串,例如 "a \" b"

"str begin \
end"

我试过了:

>>> res = re.compile('(?<=\)a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/re.py", line 190, in compile
    return _compile(pattern, flags)
  File "/usr/lib/python2.7/re.py", line 244, in _compile
    raise error, v # invalid expression

>>> res = re.compile('(?<=\)a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/re.py", line 190, in compile
    return _compile(pattern, flags)
  File "/usr/lib/python2.7/re.py", line 244, in _compile
    raise error, v # invalid expression
sre_constants.error: unbalanced parenthesis

>>> res = re.compile('(?<=\\)a')
>>> ms = res.match(r'\a')
>>> ms is None
True

实例:
当我像 ms = res.match(r'"my s\"tr"; 5;') 一样解析 "my s\"tr"; 5; 时,预期的输出是:"my s\"tr"

回答
最后 stribizhev 提供了解决方案。我认为我最初的正则表达式计算成本较低,唯一的问题是它应该使用原始字符串声明:

>>> res = re.compile(r'"([^\n"]|(?<=\)["\n])*"', re.UNICODE)
>>> ms = res.match(r'"my s\"tr"; 5;')
>>> print ms.group()
"my s\"tr"

由于 \ 是转义字符,您也需要在字符串中使用 \(转义一次),因为 python 会将 \a 解释为 十六进制 :

>>> '\a'
'\x07'

你也必须使用 re.search 因为 re.match mchecks for a match only at the beginning of the string :

>>> re.search(r'(?<=\)a','\a')
<_sre.SRE_Match object at 0x7fb704dd0370>
>>> re.search(r'(?<=\)a','\a').group(0)
'a'

但是对于你的最后一个例子,你根本不需要环顾四周,你可以使用一个简单的分组:

>>> re.search(r'"(.*)"','"my s\"tr"; 5;').group(0)
'"my s"tr"'

编辑:最终的正则表达式改编自 Word Aligned

提供的正则表达式

我认为您正在寻找这个正则表达式:

(?s)"(?:[^"\]|\.)*"

参见demo on regex101

Sample Python code(在 TutorialsPoint 上测试):

import re
p = re.compile(ur'(?s)"(?:[^"\]|\.)*"')
ms = p.match('"my s\"tr"; 5;')
print ms.group(0)

假设源代码编译,这是C和C++中匹配正则字符串字面量的经典方案,考虑到续行语法:

(?s)"(?:[^"\\n]|\.)*"

回想起来,因为我已经假设源代码可以编译,所以没有必要防止在 [^"\\n] 中不属于行继续语法一部分的杂散新行,因此仅使用 [^"\] 会也可以。

上面的正则表达式正确匹配了以下所有测试用例:

"a \" b"

"a \
 b"

"\"

"\\
kjsh\a\b\tdfkj\"\\\"

"kjsdhfksd f\\"

"kjsdhfksd f\\""

Demo on regex101

stribizhev 的旧答案 (?s)((?<!\)".+?(?<!(?<!\)\)") 无法匹配 "kjsdhfksd f\\"" 的有效案例,并且添加更多后视只能解决有限数量的 \.[=19= 的问题]

字符串文字中连续出现许多连续 \ 的可能性是这种正则表达式不起作用的原因,也是我们不应该使用拆分操作来标记带引号字段的 CSV 的原因。

一个更好的方法,如果你 "unroll" 这样的模式,你可以避免只用一个字符重复交替:

(?s)"[^"\]*(?:\.[^"\]*)*"

请注意,您也不需要使用回顾。

按照nhahtdh的建议,如果你想ensure/check所有的字符串都在一行上,你只需要从字符类中排除\n:

(?s)"[^"\\n]*(?:\.[^"\\n]*)*"