http://qs1969.pair.com?node_id=471292

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, Would any one give a hand here on how to make every first letter of a string a capital letter. I have a list of names, but they are all in capital letters, I need to make only the first letters of every word on the string to be capital.
Any help?
Like:
"THIS IS TESTING"
"JOE MARCONES"
"RESIDENTIAL MAINTENANCE COMPANY"

It has to be:
"This Is Testing"
"Joe Marcones"
"Residential Maintenance Company"

Thanks, again!

Edited by Arunbear: Changed title from 'Regular Expression', as per Monastery guidelines

Replies are listed 'Best First'.
Re: Capitalize First Letter of Each Word
by holli (Abbot) on Jun 30, 2005 at 13:04 UTC
    my @a = ( "THIS IS TESTING", "JOE MARCONES", "RESIDENTIAL MAINTENANCE COMPANY", ); s/(?<=\w)(.)/\l$1/g for @a; print join "\n", @a;
    Update: replaced \1 by $1 as per tlm's suggestion.


    holli, /regexed monk/

      Small nit: the use of backreferences like \1 in the second clause of s/// is deprecated. E.g.:

      % perl -we '$_="foo"; s/(.)/\1/' \1 better written as $1 at -e line 1.

      the lowliest monk

      Heh... these fonts are bad. When I first read this I saw slash-one dollar-one, and was trying to figure out what the heck you were smoking. Then realized \l was slash-ell... characters aren't exaclty the same but that are really close to it. :)

                      - Ant
                      - Some of my best work - (1 2 3)

        So fix your fonts and stop complaining?
Re: Capitalize First Letter of Each Word
by inman (Curate) on Jun 30, 2005 at 13:19 UTC
    #! /usr/bin/perl -w use strict; while (<DATA>) { s/\b(\w)(\w*)/uc($1).lc($2)/ge; print; } __DATA__ THIS iS a Text IN TITLE CASE THIS IS TESTING JOE MARCONES RESIDENTIAL MAINTENANCE COMPANY
      or just:
      ... s/\b(\w)(\w*)/\U$1\L$2/g ...
      no need for /ie...

      Paul

        and the \b isn't needed either as the regex will match as many word characters as possible each time.

      Mmmmmmm...

      __DATA__ This isn't right And I'm wrong too e-mail is nice when capped correctly &c
Re: Capitalize First Letter of Each Word
by halley (Prior) on Jun 30, 2005 at 15:43 UTC
    By the way, the problem as stated is fairly simple (as others have demonstrated). However, there are a LOT of patterns which probably shouldn't be capitalized at all, or should have multiple capital letters in a word.
    "Bit o' Mint" "Mano y Mano" "Chris diBona" "Scrooge McDuck" "Cruella de Ville" "Jake O'Shaunessy" "Tales from the Crypt" "Sanford and Son Salvage Company"
    Many of these cases are handled by what I call "title case." The rules vary from style guide to style guide, but as I learned them,
    • The first word is capitalized, always.
    • The last word is capitalized, always.
    • Each remaining word is capitalized, except
      • prepositions (of, by, from, ...),
      • coordinating conjunctions (and, or),
      • articles (the, a, an),
      • common foreign prepositions, conjunctions, articles.

    From there, you can try to "restore" words that fit certain patterns, but you'll probably fail. For example, "MacIntyre" but "Macintosh™." Names do not follow common grammatical or spelling rules; they are individual and a special case. Where possible, take the name's owner's spelling and don't corrupt it into all-caps in the first place.

    --
    [ e d @ h a l l e y . c c ]

Re: Capitalize First Letter of Each Word
by displeaser (Hermit) on Jun 30, 2005 at 13:51 UTC
    Hi,
    Here's another one.

    my @string =
    (
    "THIS IS TESTING",
    "JOE MARCONES",
    "RESIDENTIAL MAINTENANCE COMPANY",
    );

    @string=map(lc, @string);
    @string=map(ucfirst,@string);

    #or @string=map(ucfirst, map(lc,@string));
    print "@string\n";

    Displeaser

      A single map will suffice:

      % perl -le 'print "@{ [ map ucfirst lc, qw( ODE TO PERL ) ] }"' Ode To Perl

      the lowliest monk

        Using map implies a join of some sort. This will normalise any spaces that may have been in your original data unless the regex used to split the data is zero width.
        my $new = join '', map {ucfirst lc} split /(?=\s)/;
        No maps are needed at all. Inputting one line at a time:
        $ perl -pe 's/([A-Z]+)/ucfirst(lc $1)/egi' "THIS IS TESTING" "This Is Testing" "JOE MARCONES" "Joe Marcones" "RESIDENTIAL MAINTENANCE COMPANY" "Residential Maintenance Company" THIS iS a Text IN TITLE CASE This Is A Text In Title Case This isn't right This Isn'T Right And I'm wrong too And I'M Wrong Too e-mail is nice when capped correctly E-Mail Is Nice When Capped Correctly &c &C "Bit o' Mint" "Mano y Mano" "Chris diBona" "Scrooge McDuck" "Bit O' Mint" "Mano Y Mano" "Chris Dibona" "Scrooge Mcduck" "Cruella de Ville" "Jake O'Shaunessy" "Tales from the Crypt" "Cruella De Ville" "Jake O'Shaunessy" "Tales From The Crypt" "Sanford and Son Salvage Company" "Sanford And Son Salvage Company"
        Of course this won't and can't handle all cases. But I usually use this for small amounts of text, either to TURN OFF THE SHOUTING or to convert an all-caps title to title case, and I'm willing to correct the few errors that it leaves or produces.
        Hi
        I kindof did in my commented out line, but my aim was to make it easier for the OP to read & hopefully understand what i was doing.

        Your code is neat though. I'll ++ it tomorrow when I have some more votes ;-)

        Displeaser
Re: Capitalize First Letter of Each Word
by gube (Parson) on Jun 30, 2005 at 13:20 UTC
    @a = ("THIS IS TESTING", "JOE MARCONES", "RESIDENTIAL MAINTENANCE COMPANY", ); s#(.)(\w+)( )?#\U\1\L\2\3#gsi for @a; print join "\n", @a;
      2 points.

      1. It is save to use the ? without braces if the optional part is a single char.
      2. No need for the i and s modifier

      So that boils down to
      s#(.)(\w+ ?)#\U\1\L\2#g for @a;
      which looks actually nicer than my original post.


      holli, /regexed monk/

        It does, except it doesn't work:

        my @a = ("a sTrinG\n" ); s#(.)(\w+ ?)#\U\1\L\2#g for @a; print @a; __END__ a string

        Two things are happening here: The first is that this requires each word to be two characters or more (so it fails on the initial "a"). The second is that the . can match a space, so " sTrinG" fails because \1 contains a space.

        I suggest

        s{ \b(\w+) }{\u\L$1}gx;
        I just need to trough this here as well.
        What if I have some uncials like, "LTD" at the end of the string or on the string and it couldn't be changed
Re: Capitalize First Letter of Each Word
by Random_Walk (Prior) on Jun 30, 2005 at 13:13 UTC

    This looks like one of the infamous homework problems ... What have you tried so far ? Here is a solution that works but won't get you many marks for homework ;)

    perl -ne'$l=" ";for(split//){$_=$l eq" "?uc$_:lc$_;print;$l=$_}'

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
Re: Capitalize First Letter of Each Word
by thundergnat (Deacon) on Jun 30, 2005 at 17:01 UTC

    Most (if not all) of the solutions posted don't deal well with words with internal punctuation, and/or leading punctuation. This does. (Though it will still fail for hyphenated names like Pratt-Whitney... but I can't see any easy way to discern them from regular hyphenated words.)

    #! /usr/bin/perl use warnings; use strict; while (<DATA>) { $_ = lc $_; s/(^| )(\p{Punct}*)(\w)/$1$2\U$3/g; print; } __DATA__ THIS iS a Text IN TITLE CASE "THIS IS A 'TEST' CASE" JOE MARCONES JOE'S COMPANY holy s**t, batman! how about PARENTHETICAL TEXT (LIKE this.)
Re: Capitalize First Letter of Each Word
by AnomalousMonk (Archbishop) on Nov 19, 2014 at 11:03 UTC

    See also this recent post, perhaps by someone in the same class. Maybe seek out him or her and collaborate?