如何在正则表达式中将两个模式匹配为一个

时间:2015-01-28 07:53:53

标签: python regex

我正在使用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之间的文本,但它看起来很难看,但我不知道如何使用一个模式来获得与上面代码相​​同的结果。登记/> 谢谢!

3 个答案:

答案 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>

这将匹配\后跟上一个捕获的标记,该标记为ab

我不建议使用正则表达式来解析HTML,而是使用解析器。

答案 2 :(得分:0)

请改为使用HTML解析器(已建议TomalakMaroun 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)