Python中的正则表达式排除

3 投票
3 回答
1342 浏览
提问于 2025-04-17 01:26

我对正则表达式不太熟悉,想找一种语法来排除某些内容。我正在处理HTML代码中的<>"&(把它们替换成&lt;等),但我需要排除<br/>不被处理。

<html><br/>
   <head><title></title></head><br/>
   <body><br/>
   </body><br/>
</html>

我尝试过一些方法,比如r'<\b?![br]'之类的,但都没有完全奏效。我使用re.sub()来进行替换。

3 个回答

0

这是不是你需要的内容呢?

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>




&lt;html&gt;
    &lt;br&gt;
        &lt;title&gt;&quot;War &amp; Peace&quot;&lt;/title&gt;
        &lt;body&gt;Leon Tolstoy&lt;/body&gt;
    <br/>
&lt;/html&gt;
0

先把所有内容都替换掉,然后再进行第二次替换,把 "&lt;br/&gt;" 替换成 "<br/>"。

或者,换个说法,可以准备一个你想要“恢复”的标签列表,把 "&lt;tag&gt;" 替换成 "<tag>",把 "&lt;/tag&gt;" 替换成 "</tag>",还有把 "&lt;tag/&gt;" 替换成 "<tag/>"。

3

好的,现在这个问题又被提出来了,我可以把它当作答案来写,所以……

如果我没有理解错的话,假设只涉及到 <br/>(没有其他变体),那么可以把 <(?!br/>) 替换成 &lt;,把 (?<!<br/)> 替换成 &gt;,这样就可以了,对吧?


在 Python 中,这看起来是这样的:

text = re.sub( '<(?!br/>)' , '&lt;' , text )
text = re.sub( '(?<!<br/)>' , '&gt;' , text )


为了说明发生了什么,(?!...) 是一种负向前瞻 - 只有在后面的文本匹配它包含的子表达式时,它才会成功匹配到某个位置。
(注意,前瞻不会消耗它们子表达式匹配到的文本,它们只是验证这些文本是否存在。)

类似地,(?<!...) 是一种负向后瞻,它的作用和前瞻一样,只不过是检查前面的文本。

不过,后瞻和前瞻之间有一点不同(在某些正则表达式的实现中) - 后瞻中的子表达式必须表示固定宽度或有限宽度的匹配。

Python 就是需要固定宽度的那种语言 - 所以虽然上面的表达式可以工作(因为它总是四个字符),但如果是 (?<!<br\s*/?)>,那么在 Python 中就不是一个有效的正则表达式,因为它表示的是可变长度的匹配。(不过,你可以堆叠多个后瞻,所以如果有必要的话,你可以手动遍历各种选项。)

撰写回答