【问题标题】:Why does this regular expression only find the last available match?为什么这个正则表达式只找到最后一个可用的匹配项?
【发布时间】:2013-09-24 13:31:48
【问题描述】:
  1. 我知道,一般来说,您不应该在 HTML 中使用 Regex。我将它用作一次性工具,以快速从具有恒定模式的文件中删除一些数据,并且永远不会再次使用它。我想使用正则表达式来完成这项任务。 我了解您不应该使用 Regex 解析 HTML。
  2. 不,我不想使用 XMl Parser、BeautifulSoup、lxml 等。谢谢。 :)
  3. 我只想一次性使用它,然后永远用完。

话虽如此,我写的正则表达式只匹配文件中的最后一个“匹配”。我不确定为什么。该文件具有相当恒定的模式:

<p someAttribute="yes"><b someOtherAttribute="no">My Title - </b> My Description</p>
<p someAttribute="yes"><b someOtherAttribute="no">My 2nd Title - </b> My 2nd Description</p>
<p someAttribute="yes"><b someOtherAttribute="no">My 3rd Title - </b> My 3rd Description</p>
<p class="normal" style="margin-left:1"><b style="font-weight:400">Another one </b>The cake is a lie</p>

我不关心属性。我正在尝试对 &lt;b&gt; 标签中的内容和后面的内容进行分组。标题和说明。

def parseData(html):
    pattern = re.compile('.*<p.*><b.*>(.+)</b>(.+)</p>.*')

    matches = re.findall(pattern, str(html))

    for match in matches:
        print(match)

def main():
    htmlFile = "myFile.htm"

    browser = UrlBrowser()

    parseData(browser.getHTML(htmlFile))

此模式仅匹配最后一个可用的“匹配” - 我之前尝试添加 .* 以查看是否会出现问题,但这并没有什么不同。我在正则表达式中遗漏了什么?

【问题讨论】:

  • 它似乎工作:fiddle.re/mrban
  • "我知道您不应该使用 Regex 解析 HTML。"然而你却在搞乱它们而不是像[elem.next + elem.next.next for elem in soup.find_all("b")] 这样的东西,打字所花的时间比你发布问题所花的时间要少.. ;^) 你似乎认为使用正则表达式会不优雅但很快就可以开始工作,但这个问题本身表明并非如此。
  • 这并不是“什么是最快和最容易的”开始工作的问题,更多的是“我想尝试一下,看看我能用它做什么,即使它是乱。”我确实最终玩弄了 BeautifulSoup,但最终我以一种完全不同于 HTML 相关或正则表达式的方式完成了它。 (我确实了解了很多关于为什么说使用正则表达式。)

标签: python regex python-3.x


【解决方案1】:

应该这样做。看到这个working demo

matches = re.findall(r'<b[^>]+>(.*?)</b>(.*?)</p>', str)

正则表达式:

<b            match start of tag '<b'
 [^>]+        any character except: '>' (1 or more times)
 >            match enclosed '>'
 (            group and capture to \1:
  .*?         any character except \n (0 or more times)
 )            end of \1
 </b>         match '</b>'
 (            group and capture to \2:
  .*?         any character except \n (0 or more times)
 )            end of \2
 </p>         match '</p>'

您正在使用.*,这是贪婪的(匹配尽可能多的数量)。您想在末尾添加 ? 使其成为非贪婪(匹配尽可能少的数量)

从讨论以下量词?+???re 文档中获取解释

*、'+' 和 '?'限定符都是贪婪的;他们尽可能匹配 尽可能的文字。有时这种行为是不需要的;如果有 <.>> 匹配 '

title

',它将匹配整个 字符串,而不仅仅是 '

'。添加“?”在预选赛成功之后 以非贪婪或最小的方式进行匹配;尽可能少的字符 尽可能匹配。使用。?在前面的表达式中 仅匹配“

”。

【讨论】:

  • 你能证明它工作吗?这就是我正在努力解决的问题。
  • 这确实有效。我只是查看了我从响应中获得的输入,看起来标签并没有 100% 正确地从 response.read 中获得。你能解释一下表达式的变化吗?我正在努力提高我对正则表达式的理解。
【解决方案2】:

导致最后一场比赛的是你的领先 .*。 * 和 + 限定符将尽可能多地匹配前面的项目,同时仍然产生匹配

使用“非贪婪”*?代替每个 * 和 +?代替每个 + 以获得产生匹配的最短可能序列。

见:http://docs.python.org/3.3/library/re.html#regular-expression-syntax

【讨论】:

  • 我不认为是这样,没有.* 它仍然只抓住了最后一场比赛。
  • '.*?&lt;p.*?&gt;&lt;b.*?&gt;(.+?)&lt;/b&gt;(.+?)&lt;/p&gt;.*?' 对我来说似乎工作得很好(Python 3.3)
【解决方案3】:

还有一些事情正在发生。

import re

data = """\
<p someAttribute="yes"><b someOtherAttribute="no">My Title - </b> My Description</p>
<p someAttribute="yes"><b someOtherAttribute="no">My 2nd Title - </b> My 2nd Description</p>
<p someAttribute="yes"><b someOtherAttribute="no">My 3rd Title - </b> My 3rd Description</p>
<p class="normal" style="margin-left:1"><b style="font-weight:400">Another one </b>The cake is a lie</p>"""

print(*re.findall('.*<p.*><b.*>(.+)</b>(.+)</p>.*', data), sep="\n")
#>>> ('My Title - ', ' My Description')
#>>> ('My 2nd Title - ', ' My 2nd Description')
#>>> ('My 3rd Title - ', ' My 3rd Description')
#>>> ('Another one ', 'The cake is a lie')

请注意,开头和结尾不需要.*

print(*re.findall('<p.*><b.*>(.+)</b>(.+)</p>', data), sep="\n")
#>>> ('My Title - ', ' My Description')
#>>> ('My 2nd Title - ', ' My 2nd Description')
#>>> ('My 3rd Title - ', ' My 3rd Description')
#>>> ('Another one ', 'The cake is a lie')

'因为 Regex 已经在整个字符串中搜索匹配项。

您可能还希望更喜欢非贪婪的重复,但我认为这不是问题:

print(*re.findall('<p.*?><b.*?>(.+?)</b>(.+?)</p>', data), sep="\n")
#>>> ('My Title - ', ' My Description')
#>>> ('My 2nd Title - ', ' My 2nd Description')
#>>> ('My 3rd Title - ', ' My 3rd Description')
#>>> ('Another one ', 'The cake is a lie')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-06
    • 2018-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多