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, 2022 at 10:40
  • There are no symbols in my file Jul 29, 2022 at 10:41
  • 1
    Maybe the lowercase letter a is a better example than the uppercase letter I? Aug 4, 2022 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, 2022 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, 2022 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, 2022 at 11:32
  • 2
    You must have kept the e flag. Jul 29, 2022 at 11:45
  • 2
    Ooooh! Of course: so perl was looking for a function named U, got it. Thanks @StéphaneChazelas!
    – terdon
    Jul 29, 2022 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .