I want to replace strings between @ and . in email address when selecting from PostgreSQL.
so far I can replace @ and everything after it
select REGEXP_REPLACE(contactemail, '@(.*)(\.)?', '@xxx') from customer;
Your @(.*)(\.)? pattern matches a @, then captures into Group 1 any 0+ chars other than line break chars as many as possible, and then tries to match an optional dot, i.e. this (\.)? will never match any text but empty. It is no wonder you match all after @ with the pattern.
You need to use
SELECT REGEXP_REPLACE(col, '@[^.]*\.', '@xxx.')
Or, if you want to only remove the part of text between the closest @ and .:
SELECT REGEXP_REPLACE(col, '@[^@.]*\.', '@xxx.')
The pattern matches
@ - a @ char[^.]* - zero or more occurrences of any char but .\. - a dot.
SELECT REGEXP_REPLACE('[email protected]', '@[^\.]+\.', '@xxx.')->[email protected]