How to capitalize the first letter of each word in a string

The following examples only work for the first character of the whole string, but not of words.

s = "words are lowercase";
StringJoin[MapAt[ToUpperCase, Characters[s], 1]]   (* ==> "Words are lowercase" *)
StringReplacePart[#, ToUpperCase[StringTake[#, 1]], 1]&@s  (* ==> "Words are lowercase" *)


Is there any method along these lines to produce correct title case strings of the form:

"Words Are Lowercase"

-
See the first example in WordBoundary‌​. –  Michael E2 Sep 10 '13 at 13:24
@Kuba ah, of course, there are many many words to capitalize. –  HyperGroups Sep 10 '13 at 13:24
@MichaelE2 Ah, I think of one example in Help page. –  HyperGroups Sep 10 '13 at 13:25
To the close-voters, how exactly is this easily found in the documentation? What did you search by, or by which path did you navigate to this example? –  Mr.Wizard Sep 10 '13 at 13:36
I didn't think it should be closed, but I looked up "WordBoundary" just to check on using it to make up an answer. However, if you search for "capitalize", WordBoundary is the second hit in V9. But see István's answer - those sorts of unexpected complications are reasons such questions should not be closed, at least not right away. –  Michael E2 Sep 10 '13 at 13:54

From the documentation, though IMHO not easy to find:

StringReplace["this is a test", WordBoundary ~~ x_ :> ToUpperCase[x]]

"This Is A Test"


István Zachar highlighted a problem with WordBoundary that I'm still trying to understand. Nevertheless it seems that one can use:

strAcc = "árv ízt űr őt ük örf úr óg ép";

StringReplace[strAcc, z : (StartOfString | WhitespaceCharacter ~~ _) :> ToUpperCase[z]]

"Árv Ízt Űr Őt Ük Örf Úr Óg Ép"


It appears that the PCRE library at least as used by Mathematica does not recognize certain characters as letters. A few examples:

StringReplace[strAcc, z : RegularExpression["(?:\\A|\\s)."] :> ToUpperCase[z]]
StringReplace[strAcc, z : RegularExpression["\\b."] :> ToUpperCase[z]]

"Árv Ízt Űr Őt Ük Örf Úr Óg Ép"

"Árv Ízt űR őT Ük Örf Úr Óg Ép"  (* note odd handling *)

StringCases["abcőű", RegularExpression["\\w"]]

{"a", "b", "c"}                  (* ő and ű missing *)

-
Actually, LetterQ /@ Characters@"áéíóöőüű" returns all True, so it is only LetterCharacter that does not consider them letters... –  István Zachar Sep 10 '13 at 13:58
@IstvánZachar Thank you. I'm guessing this has something to do with compilation to PCRE. Do you happen to know if Perl considers these to be letters? –  Mr.Wizard Sep 10 '13 at 14:00
Sorry, no idea about Perl. –  István Zachar Sep 10 '13 at 14:05
This isn't a separate answer, but it's worth knowing that "Title case" usually does not capitalize certain small words, so you'd do something like: replacelittlewords = z : (StartOfString | WhitespaceCharacter ~~ # ~~ WhitespaceCharacter) :> ToLowerCase[z] & /@ {"A", "An", "The", "Is", "On", "To"} and then StringReplace[ StringReplace["This is a test about which you will be amazed", z : (StartOfString | WhitespaceCharacter ~~ _) :> ToUpperCase[z]], replacelittlewords]. –  Verbeia Sep 11 '13 at 3:18

Actually, WordBoundary won't always work correctly (see this thread):

str = "the lazy dog jumped on the quick brown fox.";
strAcc = "árv ízt űr őt ük örf úr óg ép";

StringReplace[str, WordBoundary ~~ x_ :> ToUpperCase[x]]
StringReplace[strAcc, WordBoundary ~~ x_ :> ToUpperCase[x]]

"The Lazy Dog Jumped On The Quick Brown Fox."

"Árv Ízt űR őT Ük Örf Úr Óg Ép"   (* note ű,ő instead of Ű,Ő *)


toTitleCase[str__] := StringJoin@Riffle[ToUpperCase@StringTake[#, 1] <>
ToLowerCase@StringTake[#, {2, -1}] & /@ StringSplit@StringJoin@str, " "];

toTitleCase@str
toTitleCase@strAcc

"The Lazy Dog Jumped On The Quick Brown Fox."

"Árv Ízt Űr Őt Ük Örf Úr Óg Ép"

-
Jumped on the fox? We learned it as over. :o) –  Mr.Wizard Sep 10 '13 at 13:39
@Mr.Wizard Well, obviously there were other messages sent over the Moscow-Budapest hotline... If you examine it more closely, there are further discrepancies :) (simple explanation: my memory failed me) –  István Zachar Sep 10 '13 at 13:49
Do you understand why ű is not considered a LetterCharacter? –  Mr.Wizard Sep 10 '13 at 13:51

While I endorse Mr.Wizard's pattern matching solution and I've given Istvàn +1 I would also like to submit this function which is meant to not rely on string patterns and be as readable as possible:

toTitleCase[str_] := StringJoin[
MapAt[
ToUpperCase, Characters[str],
Position[Characters[" " <> StringTrim@str], " "]
]
]

toTitleCase["the lazy dog jumped over the quick brown fox"]


"The Lazy Dog Jumped Over The Quick Brown Fox"

-
I'm sorry, but I can't endorse this. MapAt has poor algorithmic complexity, so you are shifting an operation out of an optimized domain into a known inefficient one. You have also introduced a bug in the case that there is a trailing space on the string. –  Mr.Wizard Sep 10 '13 at 18:48
@Mr.Wizard Fair enough, I didn't think about it in terms of speed especially with the sample being so tiny. :/ Fixed the problem with the trailing space though. –  Pickett Sep 10 '13 at 19:17