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



我正在使用python正则表达式进行一些正则表达式匹配。

pattern1 = re.compile('<a>(.*?)</a>[sS]*?<b>(.*?)</b>')
pattern2 = re.compile('<b>(.*?)</b>[sS]*?<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 序列不是固定的(a 可以在 b 之前或之后)。
我使用了两种模式(先尝试模式 1,然后尝试模式 2)来查找标签 a 和标签 b 之间的文本,但它看起来很丑陋,但我不知道如何使用一种模式来获得与上述代码相同的结果。
谢谢!

请不要使用正则表达式来解析 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

输出

第一次B 优先

说明:选择器a + b选择所有<b>前面直接带有<a>.prev()移动到前一个元素,即<a>(您似乎对此感兴趣 - 但仅当<b>跟随它时)。 b + a对反向元素顺序执行相同的操作。


*)首先,正则表达式不能处理无限嵌套结构,当匹配顺序不可预测时,它们会遇到问题,并且它们无法处理HTML的语义含义(字符转义序列,可选和隐式闭合元素,对不是非常严格有效的输入的宽松解析等等)。当输入采用您意想不到的形式时,它们往往会静默中断。而且,当扔到HMTL时,它们往往会变得如此复杂,以至于让任何人的头都受伤。不要花时间编写更复杂的正则表达式来解析 HTML,这是一场失败的战斗。您最终可以达到的最佳状态是那种有效但仍然不如解析器的东西。花时间学习解析器。

将其更改为:

re.compile('(?:<b>|<a>)(.*?)(?:</a>|</b>)[sS]*?(?:<a>|<b>)(.*?)(?:</a>|</b>)')

请注意,这需要更多注意,因为它与<a>匹配,后跟</b>。如果你想防止这种情况,只需抓住第一组(<a><b>)并强制它,如下所示:

<\1>

这将匹配后跟上一个捕获的标签,该标签将是 ab

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

请改用HTML解析器(正如Tomalak和Maroun Maroun已经建议的那样)。对于原因,托马拉克已经解释过了。

为了好玩,我只会为您的问题提供一个字面解决方案:

要组合两种模式,只需使用 | ,例如:

pattern = re.compile('<a>(.*?)</a>[sS]*?<b>(.*?)</b>|<b>(.*?)</b>[sS]*?<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>[sS]*?<b>(.*?)</b>|<b>(.*?)</b>[sS]*?<a>(.*?)</a>')
match = re.search(pattern, line)
print match.group(1, 2) if match.group('first') else match.group(3, 4)

最新更新