【问题标题】:how to match two pattern into one in regex如何在正则表达式中将两个模式匹配为一个
【发布时间】:2015-01-28 07:53:53
【问题描述】:

我正在使用 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 的顺序不是固定的(a 可以在 b 之前或之后)。
我使用了两种模式(先尝试模式 1,然后尝试模式 2)在标签 a 和标签 b 之间查找文本,但看起来很难看,但我不知道如何使用一种模式来获得与上述代码相同的结果。 谢谢!

【问题讨论】:

    标签: python regex


    【解决方案1】:

    请不要使用正则表达式来解析 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 选择所有&lt;b&gt;,前面直接有一个&lt;a&gt;.prev() 移动到前一个元素,即 &lt;a&gt; (您似乎对此感兴趣 - 但仅当 &lt;b&gt; 跟随它时)。 b + a 对反向元素顺序执行相同的操作。


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

    【讨论】:

      【解决方案2】:

      改成:

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

      请注意,这需要更多注意,因为它匹配&lt;a&gt;,后跟&lt;/b&gt;。如果你想防止这种情况,只需抓住第一组(&lt;a&gt;&lt;b&gt;)然后强制它,比如:

      <\\\1>
      

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

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

      【讨论】:

      • @sloth OP 需要相应地修改他们的代码。我只是想给他们一个方向。如果 OP 仍然有问题,我会编辑我的代码
      • &lt;a&gt;(.*?)&lt;/a&gt;简单地改成(?:&lt;b&gt;|&lt;a&gt;)(.*?)(?:&lt;b&gt;|&lt;a&gt;)还是错的,因为现在你匹配&lt;a&gt;Something&lt;b&gt;,原来的模式不会匹配。
      • @sloth 它不会匹配&lt;a&gt;something&lt;a&gt;a 之前应该有 \。
      • @sloth 确实,这可能是问题,一种解决方案是捕获&lt;a&gt;|&lt;b&gt; 并将其强制为封闭标签。OP 应该相应地修改他的代码。如果我不在工作,我会建议一个完整的解决方案:(
      【解决方案3】:

      请改用 HTML 解析器(正如 TomalakMaroun Maroun 已经建议的那样)。至于原因,Tomalak 已经解释过了。

      我只是为你的问题提供一个字面上的解决方案来取乐:

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

      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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-08
        • 1970-01-01
        • 2015-08-18
        • 1970-01-01
        相关资源
        最近更新 更多