4

Can I write a pattern in sed that matches patterns like Aa, Bb, Cc, etc. (i.e., Given an uppercase letter, it should match the corresponding lowercase letter) without enumerating all possibilities?

  • 2
    Can you give a sample of input/output...? – George Vasiliou Jan 25 '17 at 15:41
3

With perl, you can do:

$ echo 'fooÉébAar' | perl -Mopen=locale -pe 's/([[:upper:]])(??{lc$^N})/<$&>/g'
foo<Éé>b<Aa>r

That uses the (??{code}) special perl operator, where you can dynamically specify the regexp to match on. Here lc$^N is the lowercase version of $^N, the last capture group.

With GNU sed, you could do:

$ echo 'fooÉébAar' | sed -Ee 's/./&\L&/g;s/([[:upper:]](.)\2.)/<<\1>>/g;s/(.)./\1/g'
foo<Éé>b<Aa>r

The idea is that we first append each character in the input with their lower case version (X becomes Xx, x becomes xx), so if we see a Xxx after that (([[:upper:]](.)\2: X followed a repeated character), that means we've got an uppercase character followed by its lower case version.

Note that those would not work for characters in decomposed form. For instance for É when expressed as E followed by a combining acute accent. To work around that you could use perl's \X graphem cluster regexp operator instead:

$ printf 'E\u0301\u0302\u00e9\u0302 \u00c9e\u301 foo Ee\u301\n' |
   perl -Mopen=locale -MUnicode::Normalize -pe '
     s/((?=[[:upper:]])\X)(?{$c1 = $^N})(\X)(??{
       NFD(lc$c1) eq NFD($^N) ? qr{} : qr{(?!)}})/<$&>/g'
<É̂é̂> <Éé> foo Eé

Above using canonical normalisation forms (NFD) so that graphem clusters are always represented in the same way at the character level.

It would still fail to match on things like Fffi where that (U+FB03) is a single (typographical ligature) character but that's probably just as well anyway.

1

If you are using Sed in combination with Bash or Zsh, you can just use a small meta-program, like that:

Code

>echo "AaBCAABbEE"| sed -E "s/`echo {A..Z}|sed -E 's/\w/&\L&/g;y/ /|/'`/%/g"
%BCAA%EE

This will effectively generate all the combinations for you, using shell brace expansion (and nested sed), like illustrated below:

>echo {A..Z}|sed -E 's/\w/&\L&/g;y/ /|/'        
Aa|Bb|Cc|Dd|Ee|Ff|Gg|Hh|Ii|Jj|Kk|Ll|Mm|Nn|Oo|Pp|Qq|Rr|Ss|Tt|Uu|Vv|Ww|Xx|Yy|Zz

There are probably some pure-Sed ways of doing this too, e.g. by applying several substitutions in a row and/or using a hold space to search for these pairs one by one.

0

Combining bash and sed (in this example i use sed to match and delete the letters):

$ word="Hey , This is AaBbCc and also Dd!"

$ search="H";search2=${search,,};sed "s/[$search$search2]//g" <<<"$word"
ey , Tis is AaBbCc and also Dd!

$ search="A";search2=${search,,};sed "s/[$search$search2]//g" <<<"$word"
Hey , This is BbCc nd lso Dd!

$ search="D";search2=${search,,};sed "s/[$search$search2]//g" <<<"$word"
Hey , This is AaBbCc an also !

You just need to provide the search letter in uppercase at var "search=".

PS: If you need to search for lowercase letters then those can be transformed to uppercase with ${search^^}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.