如何在BS4"find_all"中使用regex返回具有模式优先级的匹配项



我有以下正则表达式:

import re
re.compile('|'.join([pattern1, pattern2, pattern3]))

我希望它以以下方式工作:

  • 尝试只匹配pattern1;如果匹配-停止;否则-继续
  • 尽量只匹配pattern2;如果匹配-停止;否则-继续
  • 尽量只匹配pattern3;停止

但是目前它匹配所有这些。

我找到了这个问答,我认为它回答了我的问题,但添加flags=re.I并不能解决我的问题。因为我的结果不会改变。

这怎么可能(如果有的话(?

一个可重复的例子:

from bs4 import BeautifulSoup
xml_doc = """
<m3_commodity_group commodity3="Oilseeds"><m3_year_group_Collection><m3_year_group market_year3="2011/12"><m3_month_group_Collection><m3_month_group forecast_month3=""><m3_attribute_group_Collection><m3_attribute_group attribute3="Output"><Textbox40><Cell cell_value3="353.93"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Total
Supply"><Textbox40><Cell cell_value3="429.49"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Trade"><Textbox40><Cell cell_value3="73.59"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Total
Use  2/"><Textbox40><Cell cell_value3="345.49"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Ending
Stocks"><Textbox40><Cell cell_value3="59.03"/></Textbox40></m3_attribute_group></m3_attribute_group_Collection><m3_value_group_Collection><m3_value_group><m3_attribute_group_Collection><m3_attribute_group attribute3="Output"><Textbox40><Cell Textbox44="filler"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Total
Supply"><Textbox40><Cell Textbox44="filler"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Trade"><Textbox40><Cell Textbox44="filler"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Total
Use  2/"><Textbox40><Cell Textbox44="filler"/></Textbox40></m3_attribute_group><m3_attribute_group attribute3="Ending
Stocks"><Textbox40><Cell Textbox44="filler"/></Textbox40></m3_attribute_group></m3_attribute_group_Collection></m3_value_group></m3_value_group_Collection></m3_month_group></m3_month_group_Collection></m3_year_group></m3_year_group_Collection></m3_commodity_group>
"""
soup = BeautifulSoup(xml_doc, "xml")
# This gives 11 vales.
len(soup.find_all(re.compile('|'.join([
r'^m[0-9]_commodity_group$',r'^m[0-9]_region_group$',r'^m[0-9]_attribute_group$'
]), flags=re.I)))
# This gives 1 value <-- It's what I want, but I want to achieve it with the regex from above (which would work for other texts)
len(soup.find_all(re.compile('|'.join([
r'^m[0-9]_commodity_group$'
]), flags=re.I)))
# This gives 10 values, which in this example I'd like to be ignored, since the first regex already gave results.
len(soup.find_all(re.compile('|'.join([
r'^m[0-9]_attribute_group$'
]), flags=re.I)))

您可以重组搜索:

patterns = [r'^m[0-9]_commodity_group$',r'^m[0-9]_region_group$',r'^m[0-9]_attribute_group$']
for pattern in patterns:
result = soup.find_all(re.compile(pattern, flags=re.I))
if result:
break  # Stop after the first time you found a match
else:
result = None  # When there never was a match

这可能比regex魔术更容易实现。如果您将大量执行此操作,您可能希望预编译正则表达式一次,而不是每次循环迭代。

您可以使用for循环遍历列表,如果找到匹配项则中断,而不是将所有正则表达式一起编译。

regexList = ['[abc]', '[def]', '[ghi]']
text = input()
for r in regexList:
mo = re.findall(r, text)
if mo:
break

如果您只想从正则表达式中找到1个结果,那么您可以使用repython包中的search函数。该包内置于标准python库中。

regexList = ['[abc]', '[def]', '[ghi]']
text = input()
for r in regexList:
mo = re.search(r, text)
if mo:
break

最新更新