cmscalzo
cmscalzo

Reputation: 43

(macos terminal) Changing the first letter of a regex match to uppercase

OK, I'll explain with an example:

echo "x,y (fifo(x,y) , q(x) , fifo(z))" | sed 's/f\([a-z]*\)/F\1/g'

output: x,y (Fifo(x,y) , q(x) , Fifo(z))

So basically I want to match on every word (letters only) that ends with a "(", and change the first letter of that word to uppercase. My code doesn't really work because I'd like "q(x)" to become "Q(x)" too.

In my example I do this manually by specifing "f" and "F" in the sed command (which means that it doesn't work for "q(x)") - is there a way to do this without repeating the same command for every letter in the alphabet?

GNU sed seems to have a way of making a letter uppercase, but I don't think it's supported on mac.

Thanks!

Upvotes: 2

Views: 491

Answers (3)

Ed Morton
Ed Morton

Reputation: 203684

With GNU sed for \u to convert the next letter to upper case:

$ echo "x,y (fifo(x,y) , q(x) , fifo(z))" | sed -E 's/(\w)(\w*\()/\u\1\2/g'
x,y (Fifo(x,y) , Q(x) , Fifo(z))

You can install GNU sed on macOS. Othewrise with any POSIX awk:

$ cat tst.awk
{
    head = ""
    while ( match($0,/[[:alpha:]]+\(/) ) {
        head = head substr($0,1,RSTART-1) toupper(substr($0,RSTART,1)) substr($0,RSTART+1,RLENGTH-1)
        $0 = substr($0,RSTART+RLENGTH)
    }
    print head $0
}

$ echo "x,y (fifo(x,y) , q(x) , fifo(z))" | awk -f tst.awk
x,y (Fifo(x,y) , Q(x) , Fifo(z))

Upvotes: 3

Tyl
Tyl

Reputation: 5252

For fun, figured out a macOS sed solution, the mechanism is to use a loop to switch pattern to line beginning, and uppercase first letter, then switch back.(using \r to separate)
It will be too long so I'll skip to transfer it to a one-liner.
Also it only uppercase first letter in pattern, won't lowercase following letters, so it's not strictly speaking a capitalize function. However using similar mechanism it can be done.

echo "x,y (fifo(x,y) , q(x) , fifo(z))" | sed -e '
/^[a-z][a-z]*(/breplace
:circle
/[^a-zA-Z][a-z][a-z]*(/!bend
s/\(.*[^a-zA-Z]\)\([a-z][a-z]*(.*\)/\2\r\1/
:replace
s/^a/A/
s/^b/B/
s/^c/C/
s/^d/D/
s/^e/E/
s/^f/F/
s/^g/G/
s/^h/H/
s/^i/I/
s/^j/J/
s/^k/K/
s/^l/L/
s/^m/M/
s/^n/N/
s/^o/O/
s/^p/P/
s/^q/Q/
s/^r/R/
s/^s/S/
s/^t/T/
s/^u/U/
s/^v/V/
s/^w/W/
s/^x/X/
s/^y/Y/
s/^z/Z/
/\r/s/\(.*\)\r\(.*\)/\2\1/
bcircle
:end
'

Output:

x,y (Fifo(x,y) , Q(x) , Fifo(z))

If anyone wondering, I didn't type those ses manually,
I use awk 'BEGIN{for(i=97;i<123;i++)printf "s/^%c/%c/\n", i, i-32}' created them.

Upvotes: 2

Tyl
Tyl

Reputation: 5252

It's not impossible but it's a quite hard thing for the sed on macos to do it.
Why not change to use ruby instead?(afaik ruby is preinstalled on macos, right?)
Try this:

echo "x,y (fIfo(x,y) , q(x) , fifo(z))" | ruby -ne 'print $_.gsub(/([a-z]+)(?=\()/i){$1.capitalize}'

Output:

x,y (Fifo(x,y) , Q(x) , Fifo(z))

Notice I changed to fIfo in the echo, and used i flag to ruby's regex for caseinsensitve.

Upvotes: 2

Related Questions