Python中的正则表达式排除
我对正则表达式不太熟悉,想找一种语法来排除某些内容。我正在处理HTML代码中的<
、>
、"
和&
(把它们替换成<
等),但我需要排除<br/>
不被处理。
<html><br/>
<head><title></title></head><br/>
<body><br/>
</body><br/>
</html>
我尝试过一些方法,比如r'<\b?![br]'
之类的,但都没有完全奏效。我使用re.sub()
来进行替换。
3 个回答
这是不是你需要的内容呢?
import re
import htmlentitydefs
ss = '''
<html>
<br>
<title>"War & Peace"</title>
<body>Leon Tolstoy</body>
<br/>
</html>'''
print ss
print '\n\n'
uniquechars_repl = '"&'
conditional_repl = {'<':'<(?!br/>)',
'>':'(?<!<br/)>'}
all_repl = list(uniquechars_repl) + conditional_repl.keys()
di = dict( (b,'&%s;' % a) for a,b in htmlentitydefs.entitydefs.iteritems()
if b in all_repl)
pat = '|'.join(list(uniquechars_repl) + conditional_repl.values())
text = re.sub(pat , lambda mat: di[mat.group()], ss )
print text
结果
<html>
<br>
<title>"War & Peace"</title>
<body>Leon Tolstoy</body>
<br/>
</html>
<html>
<br>
<title>"War & Peace"</title>
<body>Leon Tolstoy</body>
<br/>
</html>
先把所有内容都替换掉,然后再进行第二次替换,把 "<br/>" 替换成 "<br/>"。
或者,换个说法,可以准备一个你想要“恢复”的标签列表,把 "<tag>" 替换成 "<tag>",把 "</tag>" 替换成 "</tag>",还有把 "<tag/>" 替换成 "<tag/>"。
好的,现在这个问题又被提出来了,我可以把它当作答案来写,所以……
如果我没有理解错的话,假设只涉及到 <br/>
(没有其他变体),那么可以把 <(?!br/>)
替换成 <
,把 (?<!<br/)>
替换成 >
,这样就可以了,对吧?
在 Python 中,这看起来是这样的:
text = re.sub( '<(?!br/>)' , '<' , text )
text = re.sub( '(?<!<br/)>' , '>' , text )
为了说明发生了什么,(?!
...)
是一种负向前瞻 - 只有在后面的文本不匹配它包含的子表达式时,它才会成功匹配到某个位置。
(注意,前瞻不会消耗它们子表达式匹配到的文本,它们只是验证这些文本是否存在。)
类似地,(?<!
...)
是一种负向后瞻,它的作用和前瞻一样,只不过是检查前面的文本。
不过,后瞻和前瞻之间有一点不同(在某些正则表达式的实现中) - 后瞻中的子表达式必须表示固定宽度或有限宽度的匹配。
Python 就是需要固定宽度的那种语言 - 所以虽然上面的表达式可以工作(因为它总是四个字符),但如果是 (?<!<br\s*/?)>
,那么在 Python 中就不是一个有效的正则表达式,因为它表示的是可变长度的匹配。(不过,你可以堆叠多个后瞻,所以如果有必要的话,你可以手动遍历各种选项。)