Using negative look-ahead/behind assertion
pattern = re.compile( "(?<!\{)\{(?!\{).*?(?<!\})\}(?!\})" )
pattern.sub( "hello", input_string )
Negative look-ahead/behind assertion allows you to compare against more of the string, but is not considered as using up part of the string for the match. There is also a normal look ahead/behind assertion which will cause the string to match only if the string IS followed/preceded by the given pattern.
That's a bit confusing looking, here it is in pieces:
"(?<!\{)" #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 }
So, we're looking for a { without any other {'s around it, followed by some characters, followed by a } without any other }'s around it.
By using negative look-ahead/behind assertion, we condense it down to a single regular expression which will successfully match only single {}'s anywhere in the string.
Also, note that * is a greedy operator. It will match as much as it possibly can. If you use "\{.*\}"
and there is more than one {} block in the text, everything between will be taken with it.
"This is some example text {block1} more text, watch me disappear {block2} even more text"
becomes
"This is some example text hello even more text"
instead of
"This is some example text hello more text, watch me disappear hello even more text"
To get the proper output we need to make it non-greedy by appending a ?.
The python docs do a good job of presenting the re library, but the only way to really learn is to experiment.