My mind is blocked now, why this is not working as I expected:
$ echo 'JOHN, BO PEEP, BoPeep' | perl -0777ne 'map { print ($_) if $_ ne uc($_) } split /,/'
BoPeep
$ echo 'JOHN, BO PEEP, BoPeep' | perl -0777ne 'map { print lcfirst($_) if $_ ne uc($_) } split /,/'
BoPeep
The only difference between the two commands is print ($_) vs print lcfirst($_), while I was expecting that print lcfirst($_) would output boPeep instead.
What I'm missing?
UPDATE:
Sample input:
JOHN, BO PEEP, BoPeep, AVG, Hex_String_Literal, Time_String, MODULE
CodePudding user response:
The problem is that splitting on a comma alone leaves the leading spaces in each term.
One way to take care of that is to split on all that can come between tokens of interest, here /\s*,\s*/ (recall that split takes a full legit regex there). With other simplifications
echo "JOHN, BO PEEP, BoPeep, AVG, Hex_String_Literal, Time_String, MODULE"
| perl -nlE'$_ ne uc($_) and say lcfirst($_) for split /\s*,\s*/'
This prints words boPeep, hex_String_Literal, time_String each on a separate line. To print them as shown, on one line separated by spaces, we need a little more. For example
perl -nE'say join " ", map { $_ ne uc($_) ? lcfirst($_) : () } split /\s*,\s*/'
This uses a trick to filter by map, by passing an empty list () for all-caps words, which gets flattened into nothing in the overall output list. Or, filter then process further
perl -nE'say join " ", map { lcfirst($_) } grep { $_ ne uc($_) } split /\s*,\s*/'
This processes the list from split first to grep through it and then goes over its output list of remaining items with map, what is likely a bit less efficient than having a ternary in one pass over the whole list, but that's surely not going to show in any reasonable work loads.
Some comments
I've dropped
-0777as I am not sure of its utility -- if this runs on a file and a multiline chunks in text need be processed then we need some other provisions for that anyway. If it goes line-by-line then there's no need for it. Put it back if needed :)That convenient
-Eswitch, which providessay(and all other features!) isn't good in the eyes of future compatibility. If that is or can become an issue then useCORE::say, or of courseprint "...", "\n", and keep-einstead of-E
