python findall、分组和管道

0 投票
2 回答
1620 浏览
提问于 2025-04-16 22:41
x = "type='text'"
re.findall("([A-Za-z])='(.*?)')", x) # this will work like a charm and produce
                                     # ['type', 'text']

不过,我的问题是我想实现一个管道(选择),这样同一个正则表达式就可以适用于

x = 'type="text"' # see the quotes

基本上,下面这个正则表达式应该可以用,但用findall的时候结果却很奇怪:

([A-Za-z])=('(.*?)')|"(.*?)")

而且我不能用['"]来代替管道,因为这样可能会导致不好的结果:

value="hey there what's up?"

那么,我该如何构建一个可以同时适用于单引号和双引号的正则表达式呢?顺便说一下,请不要建议任何html或xml解析器,因为我对它们不感兴趣。

2 个回答

1

问题在于,([A-Za-z]+)=('(.*?)'|"(.*?)") 这个表达式里有四个分组,但你只需要两个(这可能就是你觉得结果奇怪的原因)。如果你用 ([A-Za-z]+)=('.*?'|".*?"),那么就没问题了。记住,你可以通过加上 (?:) 来排除分组,这样就可以写成:([A-Za-z]+)=('(?:.*?)'|"(?:.*?)")

编辑:我刚意识到这个解决方案会包含你不想要的引号。不过你可以很容易地把它们去掉。你也可以使用回溯引用,但那样会多出一个分组,最后需要把它去掉,比如:

import re
from operator import itemgetter

x = "type='text' TYPE=\"TEXT\""
print map(itemgetter(0,2), re.findall("([A-Za-z]+)=(['\"])(.*?)\\2", x)) 

这样会得到 [('type', 'text'), ('TYPE', 'TEXT')]

5

这里用 shlex 会更合适,但如果你坚持要用 re,可以试试这个表达式:([A-Za-z]+)=(?P<quote>['"])(.+?)(?P=quote)

撰写回答