在处理this answer的过程中,我偶然发现了Python重复正则表达式的异常现象。
说我给出了一个带有任意数量的引用和不带引号元素的CSV字符串:
21,2,' 23.5R25 ETADT','说明,用逗号'
我想用','
替换所有'\t'
外引号。所以我想输出:
21 \ t2 \ t' 23.5R25 ETADT' \ t'描述,用逗号'
由于字符串中会有多个匹配,我自然会使用g
正则表达式修饰符。我使用的正则表达式将匹配引号之外的字符或带引号的字符串,后跟','
:
('[^']*'|[^',]*),\s*
我将替换为:
\1\t
现在的问题是正则表达式是搜索而不是匹配所以它可以选择跳过字符直到它匹配为止。所以我得到的不是我想要的输出:
21 \ t2 \ t' 23.5R25 ETADT' \ t' description \ twith a逗号'
您可以在此处查看此行为的实际示例:https://regex101.com/r/sG9hT3/2
g
修改后的正则表达式,以便在上一次匹配后开始匹配字符?对于熟悉Perl强大正则表达式的人,Perl提供了\G
。这允许我们检索匹配的最后位置的结尾。所以在Perl中我可以用正则表达式来完成我要求的东西:
\G('[^']*'|[^',]*),\s*
这将强制最终引用元素内的不匹配。因为而不是允许正则表达式实现找到正则表达式与\G
匹配的点将强制它在第一个字符处开始匹配:
'说明,用逗号'
答案 0 :(得分:2)
您可以将以下正则表达式与re.search
:
,?\s*([^',]*(?:'[^']*'[^',]*)*)
请参阅regex demo(我将其更改为,?[ ]*([^',\n]*(?:'[^'\n]*'[^',\n]*)*)
,因为它是多行演示)
这里,正则表达式匹配(在单词的正则表达式中)......
,?
- 1或0逗号\s*
- 0个或更多空格([^',]*(?:'[^']*'[^',]*)*)
- 第1组存储由...组成的捕获文本
[^',]*
- 除,
和'
(?:'[^']*'[^',]*)*
- 0个或更多个序列...
'[^']*'
- 类似于'string'
的子字符串,不包含撇号[^',]*
- 除,
和'
以外的0个或多个字符。如果你想使用re.match
并将捕获的文本存储在捕获组中,那么由于Python正则表达式引擎不会将所有捕获存储在堆栈中,因为.NET正则表达式引擎与{{1 }}
此外,Python正则表达式不支持CaptureCollection
运算符,因此您无法在此处成功匹配结束时锚定任何子模式。
作为替代/解决方法,您可以使用以下 Python代码返回连续匹配,然后返回字符串的其余部分 :
\G
请参阅IDEONE demo,输出为
import re
def successive_matches(pattern,text,pos=0):
ptrn = re.compile(pattern)
match = ptrn.match(text,pos)
while match:
yield match.group()
if match.end() == pos:
break
pos = match.end()
match = ptrn.match(text,pos)
if pos < len(text) - 1:
yield text[pos:]
for matched_text in successive_matches(r"('[^']*'|[^',]*),\s*","21, 2, '23.5R25 ETADT', 'description, with a comma'"):
print matched_text