我正在使用python正则表达式进行一些正则表达式匹配。
pattern1 = re.compile('<a>(.*?)</a>[\s\S]*?<b>(.*?)</b>')
pattern2 = re.compile('<b>(.*?)</b>[\s\S]*?<a>(.*?)</a>')
items = re.findall(pattern1, line)
if items:
print items[0]
else:
items = re.findall(pattern2, line)
if items:
print items[0]
如您所见,标签a和b序列不固定(b之前或之后的罐头) 我使用了两个模式(首先尝试模式1,然后尝试模式2)来查找标记a和标记b之间的文本,但它看起来很难看,但我不知道如何使用一个模式来获得与上面代码相同的结果。登记/> 谢谢!
答案 0 :(得分:3)
请不要使用正则表达式来解析HTML。正则表达式不能处理HMTL (*)。 Python有不止一个很好的HTML解析器,使用其中一个。
以下示例使用pyquery,一个基于lxml的jQuery API实现。
from pyquery import PyQuery as pq
html_doc = """
<body>
<a>A first</a><b>B second</b>
<p>Other stuff here</p>
<b>B first</b><a>A second</a>
</body>
"""
doc = pq(html_doc)
for item in doc("a + b, b + a").prev():
print item.text
输出
A first B first
说明:选择器a + b
选择<b>
之前的所有<a>
。 .prev()
移动到前一个元素,即<a>
(您似乎对此感兴趣 - 但仅当<b>
跟随它时)。 b + a
对反向元素顺序执行相同的操作。
(*)例如,正则表达式无法处理无限期嵌套的构造,当匹配顺序不可预测时它们有问题,并且它们无法处理HTML的语义含义(字符转义序列,可选和隐式封闭的元素,对输入的宽松解析不是非常严格有效的等等。当输入采用您没预料到的形式时,它们往往会默默地打破。而且,当被投掷到HMTL时,他们往往会变得如此复杂,以致任何人的头部受到伤害。不要花时间编写更复杂的正则表达式来解析HTML,这是一场失败的战斗。你可以最终得到的最佳状态是某种有效的东西,但仍然不如解析器。把时间花在学习解析器上。
答案 1 :(得分:1)
将其更改为:
re.compile('(?:<b>|<a>)(.*?)(?:</a>|</b>)[\s\S]*?(?:<a>|<b>)(.*?)(?:</a>|</b>)')
请注意,这需要更多关注,因为它匹配<a>
后跟</b>
。如果你想阻止这种情况,只需抓住第一组(<a>
或<b>
)然后强制它,例如:
<\\\1>
这将匹配\
后跟上一个捕获的标记,该标记为a
或b
。
我不建议使用正则表达式来解析HTML,而是使用解析器。
答案 2 :(得分:0)
请改为使用HTML解析器(已建议Tomalak和Maroun Maroun)。为什么,托马拉克已经解释过了。
我只是为你的问题提供一个文字的解决方案:
要合并两种模式,只需使用|
,例如:
pattern = re.compile('<a>(.*?)</a>[\s\S]*?<b>(.*?)</b>|<b>(.*?)</b>[\s\S]*?<a>(.*?)</a>')
但是现在您捕获了4个组,因此您必须手动检查匹配的组。
match = re.search(patternN, line)
if match.group(1, 2) != (None, None):
print match.group(1, 2)
else:
print match.group(3, 4)
或者,更简单,使用命名组:
pattern = re.compile('<a>(?P<first>.*?)</a>[\s\S]*?<b>(.*?)</b>|<b>(.*?)</b>[\s\S]*?<a>(.*?)</a>')
match = re.search(pattern, line)
print match.group(1, 2) if match.group('first') else match.group(3, 4)