【问题标题】:python regular expression did not catch some fieldpython正则表达式没有捕获某些字段
【发布时间】:2014-07-13 04:44:14
【问题描述】:

大家好:我有一个字符串

s2 = '[u\'\\n\', <td><a href="/etf/UVXY/">UVXY</a></td>, u\'\\n\', <td><a href="/etf/
       UVXY/">Ultra VIX Short-Term Futures ETF</a></td>, u\'\\n\', <td class="rightnobr">+7'
pat = re.compile('<a href=.+>(.+)</a>')
re.findall(pat,s2) only returns ['Ultra VIX Short-Term Futures ETF']..

为什么它不能捕获字段 ['UVXY']?如果我这样做了

s22 ='[u\'\\n\', <td><a href="/etf/UVXY/">UVXY</a></td>, u\'\\n\', <td><'
re.findall(pat,s2) did return ['UVXY']

【问题讨论】:

  • 这是一种比较奇怪的输入数据格式,它是从哪里来的?
  • 输入的字符串有两行吗?
  • 或者,不使用正则表达式来匹配 HTML,这通常是一个糟糕的想法,为什么不使用像 BeautifulSoup 这样的解析器?
  • @alecxe etfdb.com/compare/volume 伙计们别担心。问题解决了
  • @XunBao 所以这是您使用正则表达式解析的 HTML。你不应该这样做,那里有 HTML 解析器。

标签: python html regex


【解决方案1】:

+ 是一个贪心运算符,所以&lt;a href=.+&gt; 将捕获&lt;a href="/etf/UVXY/"&gt;UVXY&lt;/a&gt;&lt;/td&gt;, u\'\\n\', &lt;td&gt;&lt;a href="/etf/UVXY/"&gt;,其余的将由(.+) 捕获。这就是为什么你只得到Ultra VIX Short-Term Futures ETF。你需要让它像这样不贪婪

pat = re.compile('<a href=.+?>(.+?)</a>')

输出

['UVXY', 'Ultra VIX Short-Term Futures ETF']

如果您只将第一部分设为非贪婪,则(.+) 将匹配所有内容,直到最后一个&lt;/a&gt;。所以,如果 RegEx 是

pat = re.compile('<a href=.+?>(.+)</a>')

那么输出将是

['UVXY</a></td>, u\'\\n\', <td><a href="/etf/UVXY/">Ultra VIX Short-Term Futures ETF']

这就是为什么你需要将两个贪心量词都设为非贪心,就像我的第一个例子一样。

【讨论】:

    【解决方案2】:

    .+ 是贪心匹配。 (href=.+&gt; 匹配最后一个满足模式其余部分的 &gt;)使用非贪婪版本:.+?

    >>> import re
    >>> s2 = '[u\'\\n\', <td><a href="/etf/UVXY/">UVXY</a></td>, u\'\\n\', <td><a href="/etf/UVXY/">Ultra VIX Short-Term Futures ETF</a></td>, u\'\\n\', <td class="rightnobr">+7'
    >>> pat = re.compile('<a href=.+?>(.+?)</a>')
    >>> re.findall(pat,s2)
    ['UVXY', 'Ultra VIX Short-Term Futures ETF']
    
    【解决方案3】:

    问题在于您的匹配是贪婪,其中模式消耗了最大字符。从技术上讲,实际上是量词+ 是贪婪的。要获得 non-greedy 匹配,请使用 +?

    >>> pat = re.compile('<a href=.+?>(.+?)</a>')
    >>> re.findall(pat, s2)
    ['UVXY', 'Ultra VIX Short-Term Futures ETF']
    

    您也可以考虑使用tool 来完成这项工作。

    >>> from bs4 import BeautifulSoup
    >>> soup = BeautifulSoup(s2)
    >>> links = [str(x.text) for x in soup.find_all('a')]
    ['UVXY', 'Ultra VIX Short-Term Futures ETF']
    

    【讨论】:

      【解决方案4】:

      Do not use regex for parsing HTML,使用一个叫做HTML解析器的专门工具,比如BeautifulSoup

      import urllib2
      from bs4 import BeautifulSoup
      
      URL = 'http://etfdb.com/compare/volume/'
      
      soup = BeautifulSoup(urllib2.urlopen(URL))
      for row in soup.select('table.msdata tr')[1:]:
          print [td.text.strip() for td in row('td')]
      

      打印:

      [u'SPY', u'SPDR S&P 500', u'86,697,703', u'$172,868.1 M']
      [u'EEM', u'iShares MSCI Emerging Markets ETF', u'46,298,734', u'$40,803.4 M']
      [u'IWM', u'iShares Russell 2000 ETF', u'45,452,871', u'$25,882.6 M']
      [u'QQQ', u'QQQ', u'35,422,355', u'$43,725.0 M']
      ...
      

      【讨论】:

        【解决方案5】:

        我没有足够的 StackOverflow juice 来发表评论,所以这似乎是一个答案。我经常使用在线 RE 解析器来试验和测试我的 RE。以下是更好的文档之一,其中还包含一些很好的文档:http://www.freeformatter.com/regex-tester.html

        【讨论】:

          猜你喜欢
          • 2021-07-29
          • 2011-11-21
          • 1970-01-01
          • 1970-01-01
          • 2017-05-10
          • 2019-05-31
          • 1970-01-01
          • 2011-08-13
          • 1970-01-01
          相关资源
          最近更新 更多