我正在尝试在Python中学习一些正则表达式。以下内容不会产生我预期的输出:
with open('ex06-11.html') as f:
a = re.findall("<div[^>]*id\\s*=\\s*([\"\'])header\\1[^>]*>(.*?)</div>", f.read())
# output: [('"', 'Some random text')]
我期待的输出(相同的代码,但没有反向引用):
with open('ex06-11.html') as f:
print re.findall("<div[^>]*id\\s*=\\s*[\"\']header[\"\'][^>]*>(.*?)</div>", f.read())
# output: ['Some random text']
问题实际上归结为:为什么我的第一个输出中有一个引号,但不是在我的第二个输出中?我认为([abc]) ... //1
== [abc] ... [abc]
。我不对吗?
答案 0 :(得分:7)
来自re.findall
上的文档:
如果模式中存在一个或多个组,则返回组列表;如果模式有多个组,这将是一个元组列表。
如果您希望返回整个匹配,请删除捕获组或通过在打开paren之后添加?:
将其更改为非捕获组。例如,您可以将正则表达式中的(foo)
更改为(?:foo)
。
当然,在这种情况下,您需要捕获组进行反向引用,因此最好的办法是保留当前的正则表达式,然后使用re.finditer()
的列表推导来获取仅第二组的列表:< / p>
regex = re.compile(r"""<div[^>]*id\s*=\s*(["'])header\1[^>]*>(.*?)</div>""")
with open('ex06-11.html') as f:
a = [m.group(2) for m in regex.finditer(f.read())
有几个附注,你应该考虑使用像BeautifulSoup这样的HTML解析器而不是正则表达式。如果需要在字符串中包含单引号或双引号,还应使用三引号字符串,并在编写正则表达式时使用raw string literals,这样就不需要转义反斜杠。
答案 1 :(得分:4)
行为清楚地记录在案。见re.findall
:
返回字符串中pattern的所有非重叠匹配,作为字符串列表。从左到右扫描字符串,并按找到的顺序返回匹配项。
如果模式中存在一个或多个组,则返回组列表;如果模式有多个组,这将是一个元组列表。结果中包含空匹配,除非它们触及另一场比赛的开头。
因此,如果您的正则表达式模式中有一个捕获组,那么findall
方法将返回一个元组列表,其中包含特定匹配的所有捕获组以及group(0)
。
因此,要么使用非捕获组 - (?:[\"\'])
,要么根本不使用任何组,如第二种情况。
P.S:使用raw string literals表示你的正则表达式,以避免逃避反斜杠。另外,在循环外编译你的正则表达式,这样就不会在每次迭代时重新编译。请使用re.compile
。
答案 2 :(得分:0)
当我问这个问题时,我刚开始使用正则表达式。我完全阅读了docs,我只想分享我发现的内容。
首先,Rohit和F.J建议使用原始字符串(使正则表达式更易读,更不容易出错)并使用 re.compile
即可。要匹配id为“header”的HTML字符串:
s = "<div id='header'>Some random text</div>"
我们需要一个正则表达式:
p = re.compile(r'<div[^>]*id\s*=\s*([\"\'])header\1[^>]*>(.*?)</div>')
在正则表达式的Python实现中,通过将正则表达式的一部分括在括号(...)
中来创建捕获组。捕获组捕获它们匹配的文本范围。它们也是反向引用所必需的。所以在上面我的正则表达式中,我有两个捕获组:([\"\'])
和(.*?)
。第一个需要使反向引用\1
成为可能。然而,使用反向引用(以及它们引用回捕获组的事实)会产生后果。正如在此问题的其他答案中所指出的,当在我的模式findall
上使用p
时,findall
将返回所有组的匹配并将它们放入元组列表中:
print p.findall(s)
# [("'", 'Some random text')]
由于我们只想要HTML标记之间的纯文本,因此这不是我们正在寻找的输出。
(可以说,我们可以使用:
print p.findall(s)[0][1]
# Some random text
但这可能有点人为。)
因此,为了仅返回HTML标记之间的文本(由第二组捕获),我们在group()
上使用p.search()
方法:
print p.search(s).group(2)
# Some random text
我完全清楚除了最简单的HTML之外的所有HTML都不应该由正则表达式处理,而是应该使用解析器。但这只是一个教程示例,让我掌握Python中正则表达式的基础知识。