只有在不匹配另一个正则表达式时替换正则表达式(Python)

5 投票
4 回答
2496 浏览
提问于 2025-04-15 11:43

简单来说,我有两个正则表达式。第一个用来匹配我想要替换的内容,第二个则用来匹配那些特殊情况,这些特殊情况是我不想替换的。举个简单的例子,第一个表达式是"\{.*\}",而第二个是"\{\{.*\}\}"。在这种情况下,"{this}"应该被替换成"hello",但是"{{this}}"就不应该被替换。

换句话说,有没有办法让正则表达式做到“匹配第一个字符串,但不匹配第二个字符串”,而不需要去修改第一个字符串呢?我知道我可以手动调整第一个正则表达式,让它不匹配第二个的内容,但如果第一个表达式变得越来越复杂,这样做就会变得很麻烦。

4 个回答

1

你可以把所有的{}都替换成你想要的字符串(包括{{}}的部分),然后再把{{}}替换成它自己(也就是用原来的数据覆盖第一次替换的结果)——这样的话,只有{}的部分会发生变化。

7

使用负向前瞻/后顾断言

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

负向前瞻和后顾断言让你可以对字符串的更多部分进行比较,但这并不算是占用了字符串的一部分来进行匹配。还有一种正常的前瞻和后顾断言,它会让字符串只有在被给定的模式跟随或前面的情况下才会匹配。

这看起来有点复杂,下面我们分开来看:

"(?<!\{)"  #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} 甚至更多文本"

会变成

"这是一些示例文本 hello 甚至更多文本"

而不是

"这是一些示例文本 hello 更多文本,看看我怎么消失 hello 甚至更多文本"

为了得到正确的输出,我们需要通过在后面加一个 ? 来让它变得不贪婪。

Python 的文档很好地介绍了 re 库,但真正学习的最好方法还是多多尝试。

4

你可以给替换操作提供一个函数(参考链接

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

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)

撰写回答