Python正则表达式:BackReference

时间:2012-06-10 12:16:35

标签: python regex lookahead backreference negative-lookahead

以下是Python 2.5代码(使用链接fox替换单词<a href="/fox">fox</a>,并避免在链接中替换):

import re

content="""
<div>
    <p>The quick brown <a href='http://en.wikipedia.org/wiki/Fox'>fox</a> jumped over the lazy Dog</p>
    <p>The <a href='http://en.wikipedia.org/wiki/Dog'>dog</a>, who was, in reality, not so lazy, gave chase to the fox.</p>
    <p>See &quot;Dog chase Fox&quot; image for reference:</p>
    <img src='dog_chasing_fox.jpg' title='Dog chasing fox'/>
</div>
"""

p=re.compile(r'(?!((<.*?)|(<a.*?)))(fox)(?!(([^<>]*?)>)|([^>]*?</a>))',re.IGNORECASE|re.MULTILINE)
print p.findall(content)

for match in p.finditer(content):
  print match.groups()

output=p.sub(r'<a href="/fox">\3</a>',content)
print output

输出结果为:

[('', '', '', 'fox', '', '.', ''), ('', '', '', 'Fox', '', '', '')]
('', '', None, 'fox', '', '.', '')
('', '', None, 'Fox', None, None, None)

Traceback (most recent call last):
  File "C:/example.py", line 18, in <module>
    output=p.sub(r'<a href="fox">\3</a>',content)
  File "C:\Python25\lib\re.py", line 274, in filter
    return sre_parse.expand_template(template, match)
  File "C:\Python25\lib\sre_parse.py", line 793, in expand_template
    raise error, "unmatched group"
error: unmatched group
  1. 我不确定为什么反向引用\3不起作用。

  2. (?!((<.*?)|(<a.*?)))(fox)(?!(([^<>]*?)>)|([^>]*?</a>))作品见http://regexr.com?317bn,这很令人惊讶。第一个负向前瞻(?!((<.*?)|(<a.*?)))让我感到困惑。在我看来,它不应该工作。在fox中找到它找到的第一个匹配gave chase to the fox.</p>,其中<a href='http://en.wikipedia.org/wiki/Dog'>dog</a>匹配((<.*?)|(<a.*?)),并且作为否定前瞻,它应返回FALSE。我不确定我是否清楚表达自己。

  3. 非常感谢!

    (注意:我讨厌使用BeautifulSoup。我喜欢编写自己的正则表达式。我知道很多人会说正则表达式不适合HTML处理等等。但这是一个小程序,所以我更喜欢正则表达而不是BeautifulSoup )

2 个答案:

答案 0 :(得分:3)

如果您不喜欢beautifulsoup,请尝试以下其他(X)HTML解析器之一:

html5lib
elementree
lxml

如果您计划或需要解析HTML(或变体),则值得学习这些工具。

答案 1 :(得分:1)

我不知道为什么你的表情不起作用,我注意到的唯一一件事是一开始就是一个前瞻性的小组,这对我来说没什么意义。这个似乎运作良好:

import re

content="""fox
    <a>fox</a> fox <p fox> and <tag fox bar> 
    <a>small <b>fox</b> and</a>
fox"""

rr = """
(fox)
(?! [^<>]*>)
(?!
    (.(?!<a))*
    </a
)
"""

p = re.compile(rr, re.IGNORECASE | re.MULTILINE | re.VERBOSE)
print p.sub(r'((\g<1>))', content)