4

I need all 2-3 character words completely capitalized. 1 character and 4+ character words need to be remain untouched.

Input:

cat Example
Dog
I
Fish
su
Su adm
Amd Cat ignore

Expected output:

CAT Example
DOG
a
Fish
SU
SU ADM
ADM CAT ignore
3
  • Should Let's be converted to LET's, LET'S or not converted. How about It's or i'm? IOW, how do you define word? Jul 29 at 10:40
  • There are no symbols in my file Jul 29 at 10:41
  • 1
    Maybe the lowercase letter a is a better example than the uppercase letter I? Aug 4 at 3:47

4 Answers 4

13

Using GNU sed

$ sed -E 's/\<[[:alpha:]]{2,3}\>/\U&/g' input_file
DOG
I
Fish
SU
SU ADM
AMD CAT ignore
1
  • 9
    You have to be kidding me: GNU sed even handles unicode correctly!? I tried your solution with a file containing the string sté and it correctly converted it to STÉ!
    – terdon
    Jul 29 at 11:33
7

I would use perl instead:

$ perl -pe 's/\b\w{2,3}\b/uc($&)/eg' file
CAT Example
DOG
I
Fish
SU
SU ADM
AMD CAT ignore

If your file contains non-ASCII characters encoded in UTF-8 and your locale uses UTF-8 as the charmap, for example the string sté that should become STÉ, then use:

$ perl -C -pe 's/\b\w{2,3}\b/uc($&)/eg' file
CAT Example
DOG
I
Fish
SU
SU ADM
AMD CAT ignore
STÉ
4
  • 2
    Or perl -pe's/\b\w{2,3}\b/\U$&/g', note that \w also matches on ASCII digits and underscores and only matches on ASCII letters. It would turn Stéphane to STéphane for instance. Jul 29 at 11:17
  • 2
    @StéphaneChazelas \U doesn't work for me, I always use uc() so I don't know why it fails, but it seems to be explecting a package: Can't locate object method "U" via package "cat" (perhaps you forgot to load "cat"?) at -e line 1, <> line 1. but using $& avoids the need for a capture group, so I added that. I also added a unicode aware version, thanks!
    – terdon
    Jul 29 at 11:32
  • 2
    You must have kept the e flag. Jul 29 at 11:45
  • 2
    Ooooh! Of course: so perl was looking for a function named U, got it. Thanks @StéphaneChazelas!
    – terdon
    Jul 29 at 11:48
4

This is a solution with awk:

awk '{ for (i=1; i<=NF; i++) { if (length($i) <= 3) { $i=toupper($i) } } }1' infile
2

Using Raku (formerly known as Perl_6)

raku -pe 's:g/<?wb> \w**2..3 <?wb>/{$/.uc}/;'  

OR

raku -pe 's:g/<|w> \w**2..3 <|w>/{$/.uc}/;'  

OR

raku -pe 's:g/<< \w**2..3 >>/{$/.uc}/;' 

The Raku code above is a fairly direct translation of @terdon's Perl code. Word boundaries are written either <?wb> or <|w> in Raku. These can be negated as <!wb> or <!|w>, respectively. In the last example, a left word-boundary is << and a right word boundary is >>. Raku's match variable is $/, which can also be spelled $<>.

You can change the target class from \w to <alpha> or <alnum> or even to <:Letter> (abbreviated <:L>). Nota bene: \w and <alpha> and <alnum> will match underscore while <:Letter> and <:L> will not.

All the classes mentioned immediately above are Unicode-aware so any sort of "case-folding" shouldn't be a problem. You can write regexes targeting Unicode-defined <:Ll> lowercase letters and/or Unicode-defined <:Lu> uppercase letters, and you can even compare letters with the .fc "foldcase" routine.

Sample Input:

cat Example
Dog
I
Fish
su
Su adm
Amd Cat ignore
sté
a
Xa
Xá
Xå
Xà
Xä
Xb
Xß
Xœ
Xþ

Sample Output:

CAT Example
DOG
I
Fish
SU
SU ADM
AMD CAT ignore
STÉ
a
XA
XÁ
XÅ
XÀ
XÄ
XB
XSS
XŒ
XÞ

https://docs.raku.org/language/regexes#Anchors
https://raku.org

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.