长话短说,我有两个正则表达式。一种模式匹配我想要替换的内容,另一种模式匹配那些不应替换的模式的特殊情况。举一个简单的例子,假设第一个是“\ {。* \}”,第二个是“\ {\ {。* \} \}”。然后应该替换“{this}”,但不应该“{{this}}”。是否有一种简单的方法来获取字符串并说“用”hello“替换第一个字符串的所有实例,只要它与第二个字符串不匹配”?
换句话说,有没有办法在不修改第一个字符串的情况下轻松制作“匹配第一个字符串而不是第二个字符串”的正则表达式?我知道我可以手动修改我的第一个正则表达式,从不匹配第二个正则表达式的实例,但是随着第一个正则表达式变得更加复杂,这变得非常困难。
答案 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
所以这真的是你的正则表达式可能会更精确。