如何在html字符串上控制Python的re.findall()返回的结果?

时间:2011-06-25 06:56:40

标签: python html regex lxml

我正在尝试捕获所有“Catalina 320”的实例,因为它们出现在“这些船”字符串之前(参见下面的通用示例)。

我有代码捕获“Catalina 320”的所有实例但我无法弄清楚如何在“这些船”字符串中停止它。

resultsArray = re.findall(r'<tag>(Catalina 320)</tag>', string, re.DOTALL)

任何人都可以帮我解决这个缺失的部分吗?我尝试添加'。+这些船',但它没有用。

Thanks- JD

  Blah blah blah
    <tag>**Catalina 320**</tag>
  Blah
    <td>**Catalina 320**</td>
  Blah Blah 
    <tag>**These boats** are fully booked for the day</tag>
  Blah blah blah
    <tag>Catalina 320</tag>
    <tag>Catalina 320</tag>

4 个答案:

答案 0 :(得分:3)

可以用正则表达式来解决这个问题,但是根据你所述问题的方式不需要正则表达式参见结束注释1

您应该使用lxml来解析此...

import lxml.etree as ET
from lxml.etree import XMLParser

resultsArray = []
parser = XMLParser(ns_clean=True, recover=True)
tree = ET.parse('foo.html', parser)   # See End-Note 2
for elem in tree.findall("//"):
    if "These boats" in elem.text:
        break
    elif "Catalina 320" in elem.text:
        resultsArray.append(ET.tostring(elem).strip())


print resultsArray

执行此操作会产生:

[mpenning@Bucksnort ~]$ python foo.py
['<tag>**Catalina 320**</tag>', '<td>**Catalina 320**</td>']
[mpenning@Bucksnort ~]$

<小时/> 结束注释:

  1. 您问题的当前版本没有有效标记,但我认为您有xml或html(这是您在问题的第1版中所拥有的)...我的回答可以处理您的文本as-written,但假设某些类型的结构标记更有意义,所以我使用了以下输入文本,我将其保存为foo.html:

         <body>
    <tag>Blah blah blah</tag>
        <tag>**Catalina 320**</tag>
      <tag>Blah<tag>
        <td>**Catalina 320**</td>
      </tag>Blah Blah </tag>
        <tag>**These boats** are fully booked for the day</tag>
      <tag>Blah blah blah</tag>
        <tag>Catalina 320</tag>
        <tag>Catalina 320</tag>
        </body>
    
  2. 如果您想更加关注编码问题,可以在使用lxml.soupparser

  3. 解析HTML时使用lxml作为后备广告

    from lxml.html import soupparser
    # ...
    try:
        parser = XMLParser(ns_clean=True, recover=True)
        tree = ET.parse('foo.html', parser)
    except UnicodeDecodeError:
        tree = soupparser.parse('foo.html')
    

答案 1 :(得分:2)

如果您的问题没有其他背景,您可以在第一次出现'These boats'之前进行搜索:

re.findall('Catalina 320', string.split('These boats')[0])

答案 2 :(得分:0)

groups = re.findall(r'(Catalina 320)*.*These boats, r.read(), re.DOTALL)

组中的第一组将包含Catalina 320匹配列表。

答案 3 :(得分:-1)

名称'foo.html'的文件包含

     <body>
<tag>Blah blah blah</tag>
    <tag>**Catalina 320**</tag>
  <tag>Blah<tag>
    <td>**Catalina 320**</td>
  </tag>Blah Blah </tag>
    <tag>**These boats** are fully booked for the day</tag>
  <tag>Blah blah blah</tag>
    <tag>Catalina 320</tag>
    <tag>Catalina 320</tag>
    </body>

代码:

from time import clock
n = 1000


########################################################################

import lxml.etree as ET
from lxml.etree import XMLParser

parser = XMLParser(ns_clean=True, recover=True)
etree = ET.parse('foo.html', parser)

te = clock()
for i in xrange(n):
    resultsArray = []
    for thing in etree.findall("//"):
        if "These boats" in thing.text:
            break
        elif "Catalina 320"in thing.text:
            resultsArray.append(ET.tostring(thing).strip())
tf = clock()

print 'Solution with lxml'
print tf-te,'\n',resultsArray


########################################################################

with open('foo.html') as f:
    text = f.read()

import re


print '\n\n----------------------------------'
rigx = re.compile('(Catalina 320)(?:(?:.(?!Catalina 320))*These boats.*\Z)?',re.DOTALL)

te = clock()
for i in xrange(n):
    yi = rigx.findall(text)
tf = clock()

print 'Solution 1 with a regex'
print tf-te,'\n',yi


print '\n----------------------------------'

ragx = re.compile('(Catalina 320)|(These boats)')

te = clock()
for i in xrange(n):
    li = []
    for mat in ragx.finditer(text):
        if mat.group(2):
            break
        else:
            li.append(mat.group(1))
tf = clock()

print 'Solution 2 with a regex, similar to solution with lxml'
print tf-te,'\n',li


print '\n----------------------------------'

regx = re.compile('(Catalina 320)')

te = clock()
for i in xrange(n):
    ye = regx.findall(text, 0, text.find('These boats') if 'These boats' in text else len(text)) 
tf = clock()

print 'Solution 3 with a regex'
print tf-te,'\n',ye

结果

Solution with lxml
0.30324105438 
['<tag>**Catalina 320**</tag>', '<td>**Catalina 320**</td>']


----------------------------------
Solution 1 with regex
0.0245033935877 
['Catalina 320', 'Catalina 320']

----------------------------------
Solution 2 with a regex, similar to solution with lxml
0.0233258696287
['Catalina 320', 'Catalina 320']

----------------------------------
Solution 3 with regex
0.00784708671074 
['Catalina 320', 'Catalina 320']

我的解决方案中使用正则表达式错误是什么

  

时代:

     

lxml - 100%

     

解决方案1 ​​ - 8.1%

     

解决方案2 - 7.7%

     

解决方案3 - 2.6%

使用正则表达式不要求文本是XML或HTML文本。

那么,假装正则表达式不如lxml来处理这个问题的剩余参数是什么?

编辑1

rigx = re.compile('(Catalina 320)(?:(?:.(?!Catalina 320))*These boats.*\Z)?',re.DOTALL)的解决方案并不好:

这个正则表达式将捕获'Catalina 320'的出现位于'这些船'后如果没有出现'Catalina 320'之前'这些船'< / p>

模式必须是:

rigx = re.compile('(<tag>Catalina 320</tag>)(?:(?:.(?!<tag>Catalina 320</tag>))*These boats.*\Z)?|These boats.*\Z',re.DOTALL)

但与其他解决方案相比,这是一个相当复杂的模式