如何在 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)"(?:[^"\]|\.)*"
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\\""
stribizhev 的旧答案 (?s)((?<!\)".+?(?<!(?<!\)\)")
无法匹配 "kjsdhfksd f\\""
的有效案例,并且添加更多后视只能解决有限数量的 \
.[=19= 的问题]
字符串文字中连续出现许多连续 \
的可能性是这种正则表达式不起作用的原因,也是我们不应该使用拆分操作来标记带引号字段的 CSV 的原因。
一个更好的方法,如果你 "unroll" 这样的模式,你可以避免只用一个字符重复交替:
(?s)"[^"\]*(?:\.[^"\]*)*"
请注意,您也不需要使用回顾。
按照nhahtdh的建议,如果你想ensure/check所有的字符串都在一行上,你只需要从字符类中排除\n
:
(?s)"[^"\\n]*(?:\.[^"\\n]*)*"
如何使用后向断言在 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)"(?:[^"\]|\.)*"
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\\""
stribizhev 的旧答案 (?s)((?<!\)".+?(?<!(?<!\)\)")
无法匹配 "kjsdhfksd f\\""
的有效案例,并且添加更多后视只能解决有限数量的 \
.[=19= 的问题]
字符串文字中连续出现许多连续 \
的可能性是这种正则表达式不起作用的原因,也是我们不应该使用拆分操作来标记带引号字段的 CSV 的原因。
一个更好的方法,如果你 "unroll" 这样的模式,你可以避免只用一个字符重复交替:
(?s)"[^"\]*(?:\.[^"\]*)*"
请注意,您也不需要使用回顾。
按照nhahtdh的建议,如果你想ensure/check所有的字符串都在一行上,你只需要从字符类中排除\n
:
(?s)"[^"\\n]*(?:\.[^"\\n]*)*"