Case matching pattern replacement with sed

awksedtext processing

I have a source code spread across several files.

  • It has a pattern abcdef which I need to replace with pqrstuvxyz.
  • The pattern could be Abcdef (Sentence Case) then it needs to be replaced with Pqrstuvxyz.
  • The pattern could be AbCdEf (Toggle case) then it needs to be replaced with PqRsTuVxYz.

In short, I need to match the case of the source pattern and apply the appropriate destination pattern.

How can I achieve this using sed or any other tool?

Best Answer

Portable solution using sed:

sed '
:1
/[aA][bB][cC][dD][eE][fF]/!b
s//\
&\
pqrstu\
PQRSTU\
/;:2
s/\n[[:lower:]]\(.*\n\)\(.\)\(.*\n\).\(.*\n\)/\2\
\1\3\4/;s/\n[^[:lower:]]\(.*\n\).\(.*\n\)\(.\)\(.*\n\)/\3\
\1\2\4/;t2
s/\n.*\n//;b1'

It's a bit easier with GNU sed:

search=abcdef replace=pqrstuvwx
sed -r ":1;/$search/I!b;s//\n&&&\n$replace\n/;:2
    s/\n[[:lower:]](.*\n)(.)(.*\n)/\l\2\n\1\3/
    s/\n[^[:lower:]](.*\n)(.)(.*\n)/\u\2\n\1\3/;t2
    s/\n.*\n(.*)\n/\1/g;b1"

By using &&& above, we reuse the case pattern of the string for the rest of the replacement, So ABcdef would be changed to PQrstuVWx and AbCdEf to PqRsTuVwX. Change it to & to affect only the case of the first 6 characters.

(note that it may not do what you want or may run into an infinite loop if the replacement may be subject to substitution (for instance if substituting foo for foo, or bcd for abcd)

Related Question