Other solutions mix regex syntaxes. To use perl/PCRE patterns for both search and replace, and only process matching files, this works quite well:
grep -rlIZPi 'match1' | xargs -0r perl -pi -e 's/match2/replace/gi;'
match1 and match2 are usually identical but match1 can be simplified to remove more advanced features that are only relevant to the substitution, e.g. capturing groups.
Translation: grep recursively and list matching filenames, each separated by nul to protect any special characters; pipe any filenames to xargs which is expecting a nul-separated list; if any filenames are received, pass them to perl to perform the actual substitutions.
For case-sensitive matching, drop the i flag from grep and the i pattern modifier from the s/// expression, but not the i flag from perl itself. Remove the I flag from grep to include binary files.
sed -i 's/.*substring.*/replace/'- Eddy_Emsed -i 's/\(.*\)substring\(.*\)/\1replace\2/'- JStrahl