只有在不匹配另一个正则表达式时替换正则表达式(Python)
简单来说,我有两个正则表达式。第一个用来匹配我想要替换的内容,第二个则用来匹配那些特殊情况,这些特殊情况是我不想替换的。举个简单的例子,第一个表达式是"\{.*\}",而第二个是"\{\{.*\}\}"。在这种情况下,"{this}"应该被替换成"hello",但是"{{this}}"就不应该被替换。
换句话说,有没有办法让正则表达式做到“匹配第一个字符串,但不匹配第二个字符串”,而不需要去修改第一个字符串呢?我知道我可以手动调整第一个正则表达式,让它不匹配第二个的内容,但如果第一个表达式变得越来越复杂,这样做就会变得很麻烦。
4 个回答
你可以把所有的{}都替换成你想要的字符串(包括{{}}的部分),然后再把{{}}替换成它自己(也就是用原来的数据覆盖第一次替换的结果)——这样的话,只有{}的部分会发生变化。
使用负向前瞻/后顾断言
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 库,但真正学习的最好方法还是多多尝试。
你可以给替换操作提供一个函数(参考链接)
但要确保第一个正则表达式包含第二个正则表达式。这只是一个例子:
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)