2

I have the following list of items:

bigBone
fishMarket
dogCollar
...

I need to generate a two character mapping like this:

bigBone -> bb
fishMarket -> fm
dogCollar -> dc
...

How can I create the above mapping using sed?

I have tried something like:

sed -i -r 's/^([a-z]{1})[a-z]+([A-Z]{1})[a-zA-Z]+/ -> \1\L\2/' file

I saw this question, but not sure how to incorporate the concept here. Thanks.

  • See the comment of Stephane Chazelas to my answer. – Hauke Laging May 6 '14 at 9:11
4

If I understand you correctly then you want to keep the whole line and just append something:

sed -r 's/^([a-z]{1})([a-z]+)([A-Z]{1})([a-zA-Z]+)$/\1\2\3\4 -> \1\L\3/' file

edit:

devnull had to remind me of it that there is an easy solution to this:

sed -r 's/^([a-z]{1})[a-z]+([A-Z]{1})[a-zA-Z]+/& -> \1\L\2/' file

Or, a bit more elegant (than my first try):

sed -r '
h
s/^([a-z]{1})[a-z]+([A-Z]{1})[a-zA-Z]+/ -> \1\L\2/
t append
b
: append
H
g
s/\n//' file
  • @QuestionOverflow It is even simpler, see the edit. – Hauke Laging May 6 '14 at 8:39
  • 2
    ranges like [a-z] only make sense in the POSIX or C locales. So you'd want either LC_ALL=C sed ... or to use [[:lower:]] instead. Note that {1} is redundant. – Stéphane Chazelas May 6 '14 at 9:05
4

Using GNU sed:

sed -r 's/(.)[^[:upper:]]*(.).*/& -> \1\L\2/' inputfile

For your input, it'd produce:

bigBone -> bb
fishMarket -> fm
dogCollar -> dc
3

To generalise to fooBarBaz -> fbb, abCdEfGh -> aceg, with GNU sed:

sed -r 's/(.)(.*)/\1\n\2 -> \L\1/;:1
        s/\n([^[:upper:]]*([[:upper:]]))(.*)/\1\n\3\L\2/;t1;s/\n//'

POSIX sed doesn't have \L. So portably, you'd have to resort to using y and manually enter all the characters you want converted to lowercase. Something like:

LC_ALL=C sed '/^\([[:alpha:]]\).*/{
h;s//\1/;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;G
s/\(.\).\(.\)\(.*\)/\2\
\3 -> \1/;:1
/.*\n[^A-Z]*\([A-Z]\).*/{h;s//\1/
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;G
s/^\(.\)\n\(.*\)\n\([^A-Z]*[A-Z]\)\(.*\)/\2\3\
\4\1/;t1
}
s/\n//;}'
2

Here it is with a POSIX compliant script. I wasn't aware that POSIX sed leaves the behavior of s///[n]g unspecified, but, sure enough, it is not a well-defined behavior. Anyway, it's easy to handle without it - I just don't like using too many back-references if it can be helped, usually.

sed '/^[a-z]*[A-Z].*$/{ h
    s/\(.\)[^A-Z]*/\1/g
    y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
    H ; g 
    s/\n/ -> /
    }' <<\DATA
bigBone
fishMarket
dogCollar
DATA

#OUTPUT
bigBone -> bb
fishMarket -> fm
dogCollar -> dc
  • 1
    Have you tried that? Doesn't work here (upper case vs. lower case)). – Hauke Laging May 6 '14 at 7:44
  • 1
    @HaukeLaging - I just needed to fix y/ - it would have worked as it was if I had used -r but there's no need whatsoever to write a non-portable script for such a simple application. If it was you who downvoted this post and you did so due to the case conversion, that issue is resolved, and it is now faster and more portable than your own script. I believe you should reverse that vote. – mikeserv May 6 '14 at 7:57
  • @HaukeLaging - even better now. Thank you, Hauke. I expect that was you. – mikeserv May 6 '14 at 8:18
  • 1
    \L is GNU specific anyway, so you might as well use -r – Stéphane Chazelas May 6 '14 at 9:24
  • 1
    Seriously, @StephaneChezales? OR\| isnt portable? I got both of those from the Grymoire. And its pretty old, too. I think hes even got a letter or two from you in that manual of his in there somewhere... I thought it was portable code. I can easily do it without it. Im just... Kinda done with it... Oh well, ill fix it. By the way - have you got the sed specs memorized or something? I couldnt remember all of those ins and outs like that. Youre definitely one of a kind. – mikeserv May 6 '14 at 16:53
1

This answer is just similar to @devnull's,

$ sed 's/\(.\).*\([A-Z]\).*/& -> \1\L\2/g' file
bigBone -> bb
fishMarket -> fm
dogCollar -> dc
1

If you can use perl, try:

$ perl -MList::Util=first -F// -aple '$_ .= " -> ".$F[0].lc(first{ord() < 97} @F)' file
bigBone -> bb
fishMarket -> fm
dogCollar -> dc

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.