2011-09-04 126 views
3

我不能用正则表达式,我正在寻找排除某些东西的语法。 我解析<,>,"&在html代码(用&lt;等取代),我需要排除<br/>从解析。 即:Python中的正则表达式排除

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

我试着像sometihng即:r'<\b?![br]'等人,但他们并不完全工作。我用re.sub()来代替。

+0

我不能也不想安装外部库。 – stdio

+2

@stdio你不需要外部库; Python附带了开箱即用的ElementTree(lxml提供了更好的实现的API)。 –

+1

XML(像它扩展的SGML)不是一种常规语言(在计算机科学中这个术语的含义 - 如果你已经参加了编译器设计课程,他们应该进入它)。正则表达式不足以解析它。 –

回答

2

好了,现在的问题是重新开放,我可以做到这一点作为一个答案,所以......

除非我失去了一些东西,而一旦它只是<br/>(没有任何变体),则可以只替换<(?!br/>)&lt;(?<!<br/)>&gt;这就是它?


在Python,它看起来像这意味着这样的:

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


为了解释这是怎么回事,(?! ...... )是负前瞻 - 它只有在成功当一个位置相匹配以下文字不是与其包含的子表达式匹配。
(注向前看符号不消耗由他们的子表达式匹配的文本,他们只当它不存在,或者无法核实。)

同样,(?<! ... )是负的样子背后和做同样的事情,但使用前面的文字。

但是,lookbeheads与lookaheads(在一些正则表达式实现中)略有不同 - 也就是说,lookbehinds内部的子表达式必须表示固定宽度或有限宽度的匹配。

Python是需要固定宽度的那个 - 所以虽然上面的表达式工作(因为它总是四个字符),如果它是(?<!<br\s*/?)>那么它不会是Python的有效正则表达式,因为它表示一个可变长度比赛。 (但是,可以将堆叠多个向后看,所以如果需要,您可以手动迭代各种选项。)

+0

我已经说过:完美;)现在,有没有一种方法可以做到一步到位?对于正则表达式没有问题,我可以使用'或'运算符(|),但有没有办法将re.sub()作为第二个参数传递给多个值? – stdio

+1

你用不同的东西代替,所以你不能一步到位。那么,我认为PHP允许你传递一个数组(对于正则表达式和替换),但是这在Python文档中没有提及,所以如果它很重要的话,需要用户定义的函数。当然,如果仅仅是一个不想临时的情况,你也可以做're.sub('<(?!br/>)','<',re.sub('(?','>',text))'变量。 –

+0

简单而好的解决方案。再次感谢 :) – stdio

0

替换一切,然后在第二遍替换“& lt; br/& gt;”与“< br/>”。

或者,为了一般化,有一个你想'恢复'的标签列表并替换为“& lt; tag & gt;”与“<标记>”,“& lt;/tag & gt;”与“< /标记>”和“& lt; tag/& gt;” “< tag/>”。

+1

更美好更优雅的东西?但是我更喜欢使用正则表达式。 – stdio

+0

@stdio:但这个答案*使用正则表达式。一旦你完成了所有的转换,只需撤消你不想改变的标签即可。 – tchrist

+0

@tchrist:是的,但它并不优雅,我更喜欢使用re.sub()在一个步骤中完成所有操作(不包括通过正则表达式的'br'标记解析)。 – stdio

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;