Capitalize the first letter of all words in a String A rags-to-riches of A method to capitalize the first letter of all words in a String.

To recap the requirements:


  Please implement this method to capitalize all first letters of the words in the given String. All other symbols shall remain intact. If a word starts not with a letter, it shall remain intact too. Assume that the parameter String can only contain spaces and alphanumeric characters.
  
  NOTE: please keep in mind that the words can be divided by single or multiple spaces.The spaces also can be found at the beginning or the end of the parameter string,and you need to preserve them.


And the code:

public class Main
{
    public static void main(String... args) {
        for(String arg : args) {
            System.out.println(titleize(arg));
        }
    }

    /**
     * Titleize a string. Takes a string and returns a new string where all words
     * have had their first letter title cased. If the letter is already title case
     * or is not a cased letter (like a number), it will be passed through.
     * Leading, trailing, and all other whitespace is preserved.
     *
     * This method is not as robust as titleize in Rails. It does not do any magic
     * like breaking up MashedTogetherWords or replacing_underscores.
     *
     * This will blow up if null is passed in.
     */
    public static String titleize(final String input) {
        // Initialize the output to the length of the input since we know it and the
        // output and input will be the same size.
        StringBuilder output = new StringBuilder(input.length());
        // This defaults to true because we assume the beginning of the
        // string also counts as whitespace. This is to make sure the
        // first word gets capitalized as well.
        boolean lastCharacterWasWhitespace = true;

        for(int i = 0; i &lt; input.length(); i++) {
            char currentCharacter = input.charAt(i);

            if(lastCharacterWasWhitespace &amp;&amp; Character.isLowerCase(currentCharacter)) {
                currentCharacter = Character.toTitleCase(currentCharacter);
            }

            output.append(currentCharacter);

            lastCharacterWasWhitespace = Character.isWhitespace(currentCharacter);
        }

        return output.toString();
    }
}


The original code tried to use regular expressions and splitting words to accomplish the task. This does neither. It was partially inspired by the accepted answer, by treating the String as a stream of characters.

This is Java 7. I'm sure there's some Java 8 stream fanciness that can do this in half the lines.
This is a cool little problem that needs Java8, and regex. ... promise.

First up, the Pattern.splitAsStream(...) method is new in Java8, and converts a string in to a stream of substrings, depending on the pattern, so, what's the pattern?

Well, the pattern is to match the beginning of any word that needs to be capitalized. Your code currently finds characters, after whitespace, but that is, as you admit, too naive. Words that need capitalization are things like:


This is 'quoted' -> This Is 'Quoted'
This has-joined-words -> This Has-Joined-Words
This should not 1800not1337 -> This Should Not 1800not1337


and so on.

So, your code would not deal well with the above examples.... but, how can it be better?

private static final Pattern bound = Pattern.compile("\\b(?=\\w)");


The above regular expression looks for a word-boundary that is followed by a character (where "a character" is a letter, digit, or underscore).

Then, you have a sequence of sentence parts that need captialization, and it can be streamed easily:

private static final Pattern bound = Pattern.compile("\\b(?=\\w)");

private static final String ucFirst(String input) {
    return input.substring(0,  1).toUpperCase() + input.substring(1);
};

public static String titleize(final String input) {
    return bound.splitAsStream(input)
          .map(StringCap::ucFirst)
          .collect(Collectors.joining());
}


You can see this running here: http://ideone.com/ilmBqi



Note: Using Java7 versions of Pattern matchers, it is also actually quite easy.... Consider this pattern, which stores the first-character as a pattern group, and then the "traditional" matching replacement loop:

private static final Pattern bound = Pattern.compile("\\b(\\w)");

public static String titleize(final String input) {
    StringBuffer sb = new StringBuffer(input.length());
    Matcher mat = bound.matcher(input);
    while (mat.find()) {
        mat.appendReplacement(sb, mat.group().toUpperCase());
    }
    mat.appendTail(sb);
    return sb.toString();
}


The above is able to capitalize the words in the same output as the Java8 version above.