仅当它与另一个正则表达式(Python)不匹配时才替换正则表达式

时间:2009-05-20 16:45:00

标签: python regex

长话短说,我有两个正则表达式。一种模式匹配我想要替换的内容,另一种模式匹配那些不应替换的模式的特殊情况。举一个简单的例子,假设第一个是“\ {。* \}”,第二个是“\ {\ {。* \} \}”。然后应该替换“{this}”,但不应该“{{this}}”。是否有一种简单的方法来获取字符串并说“用”hello“替换第一个字符串的所有实例,只要它与第二个字符串不匹配”?

换句话说,有没有办法在不修改第一个字符串的情况下轻松制作“匹配第一个字符串而不是第二个字符串”的正则表达式?我知道我可以手动修改我的第一个正则表达式,从不匹配第二个正则表达式的实例,但是随着第一个正则表达式变得更加复杂,这变得非常困难。

4 个答案:

答案 0 :(得分:6)

使用否定前瞻/后方断言

pattern = re.compile( "(?<!\{)\{(?!\{).*?(?<!\})\}(?!\})" )
pattern.sub( "hello", input_string )

负向前瞻/后方断言允许您与更多字符串进行比较,但不会被视为用尽匹配的字符串的一部分。还有一个正常的向前/向后断言,只有在字符串IS跟随/前置给定模式时才会使字符串匹配。

看起来有点令人困惑,这里有点:

"(?<!\{)"  #Not preceded by a {
"\{"       #A {
"(?!\{)"   #Not followed by a {
".*?"      #Any character(s) (non-greedy)
"(?<!\})"  #Not preceded by a } (in reference to the next character)
"\}"       #A }
"(?!\})"   #Not followed by a }

所以,我们正在寻找一个{没有任何其他的',然后是一些字符,然后是},而没有任何其他}围绕它。

通过使用负向前瞻/后方断言,我们将其压缩为单个正则表达式,该表达式将成功匹配字符串中任何位置的单个{}。

另外,请注意*是一个贪婪的运算符。它将尽可能多地匹配。如果你使用"\{.*\}"并且文本中有多个{}块,那么它们之间的所有内容都会被使用。

  

“这是一些示例文本{block1}更多文字,看着我消失{block2}更多文字”

变为

  

“这是一些示例文本你好更多的文字”

而不是

  

“这是一些示例文本你好更多的文字,看着我消失你好更多的文字”

要获得正确的输出,我们需要通过添加?。

使其变得非贪婪

python docs可以很好地呈现re库,但真正学习的唯一方法就是实验。

答案 1 :(得分:4)

您可以提供替换功能(reference

但请确保第一个正则表达式包含第二个正则表达式。这只是一个例子:

regex1 = re.compile('\{.*\}')
regex2 = re.compile('\{\{.*\}\}')

def replace(match):
    match = match.group(0)
    if regex2.match(match):
        return match
    return 'replacement'


regex1.sub(replace, data)

答案 2 :(得分:1)

您可以用替换字符串替换所有{}实例(包括{{}}字符串),然后用自己的后引用替换{{}}实例(覆盖第一个替换字符串)原始数据) - 然后只有{}实例会发生变化。

答案 3 :(得分:0)

当你正在寻找的是真正的一种模式时,我觉得它与两种不同的正则表达式匹配是次优的。举例说明:

import re
foo = "{{this}}"
bar = "{that}"
re.match("\{[^\{].*[^\}]\}", foo)  # gives you nothing
re.match("\{[^\{].*[^\}]\}", bar)  # gives you a match object

所以这真的是你的正则表达式可能会更精确。