I believe a negative lookahead assertion will do what you want:
import re
regex = r'<(?!/?QUOTE\b)[^>]+>'
tests = [
'a plain old string',
'a string with <SOME> <XML TAGS="stuff">',
'a string with <QUOTE>, </QUOTE>, and <QUOTE with="data">',
'a string that has <QUOTEA> tags </QUOTEB>',
]
for i in tests:
result = re.sub(regex, '', i)
print('{}\n{}\n'.format(i, result))
EDIT: How it works
Lookahead assertions, as the name suggests, "look ahead" in the string being matched, but don't consume the characters they're matching. You can do positive ((?=...)) and negative ((?!...)) lookaheads. (There are also positive and negative lookbehind assertions.)
So, the regex shown matches < for the beginning of a tag, then does a negative lookahead for QUOTE with an optional / before it (/?) and a word boundary behind it (\b). If that's matched, the regex does not match, and that tag is ignored. If it's not matched, the regex goes on to eat one or more non-> characters, and the closing >. I guess you might want to have it eat any whitespace following the tag, too - I didn't do that.