Search code examples
javastringsubroutinecapitalization

Subroutine Returns all Capitals on a String Paramter, Should only be first letter


One of my problem sets requires me to take create a subroutine that will take a String variable as a parameter and return that same string except with the first letter of each word capitalized. The examples in the text use non-standard class the Professor specifically designed. I don't want to do this as I would think it makes more sense to learn with standard classes than see what else is out there. The problem I am having though is my subroutine is returning a String in all capitals. Here is my code:

import java.util.Scanner;

public class Capitalize {

static String capitalizeString(String x) {

    String completedConversion = "";

    for (int i=0; i < x.length(); i++) {

        if (i == 0) {
            char ch = x.charAt(i);
            ch = Character.toUpperCase(ch);
            completedConversion = completedConversion + ch;
            i++;
        }

        if (Character.isLetter(i - 1)) {

            char ch = x.charAt(i);
            completedConversion = completedConversion + ch;
         }

        else {

            char ch = x.charAt(i);
            ch = Character.toUpperCase(ch);
            completedConversion = completedConversion + ch;
        }

    }

    return completedConversion;

} // End of subroutine

I have not yet added any commenting etc. but it should be pretty straightforward.

SOLVED: Using Keammoort's answer

public class Capitalize {

    static String capitalizeString(String x) {

        String completedConversion = "";

        for (int i=0; i < x.length(); i++) {

            if (i == 0) {
                char ch = x.charAt(i);
                ch = Character.toUpperCase(ch);
                completedConversion = completedConversion + ch;
            }

            else if (!Character.isWhitespace(x.charAt(i - 1))) {

                char ch = x.charAt(i);
                completedConversion = completedConversion + ch;

            }

            else {

                char ch = x.charAt(i);
                ch = Character.toUpperCase(ch);
                completedConversion = completedConversion + ch;
            }

        }

return completedConversion;

Solution

  • Identifying the problem

    This part code causes problems:

    if (Character.isLetter(i - 1)) {
        char ch = x.charAt(i);
        completedConversion = completedConversion + ch;
    } else {
        char ch = x.charAt(i);
        ch = Character.toUpperCase(ch);
        completedConversion = completedConversion + ch;
    }
    

    First of all method Character.isLetter() with parameter of type int returns true when passed parameter converted to a character (using codePoint) is a letter character. So for quite a few initial iterations you'll get a false. If Character.isLetter() returns false then you're changing a leter to uppercase anyway.

    Getting actual character

    I think there should be:

    if (Character.isLetter(x.charAt(i - 1))) { //added getting character from input String
        char ch = x.charAt(i);
        completedConversion = completedConversion + ch;
    } else {
        char ch = x.charAt(i);
        ch = Character.toUpperCase(ch);
        completedConversion = completedConversion + ch;
    }
    

    Using isWhitespace() instead of isLetter()

    Even better: use isWhitespace() method. It will prevent situations when a digit is inside a word (then character after digit would be uppercase too).

    if (!Character.isWhitespace(x.charAt(i - 1))) {
        //if previous char is not a whitespace don't change case
        char ch = x.charAt(i);
        completedConversion = completedConversion + ch;
    } else {
        //if previous char is a whitespace change to uppercase
        char ch = x.charAt(i);
        ch = Character.toUpperCase(ch);
        completedConversion = completedConversion + ch;
    }
    

    Then all characters that are right after spaces, tabs, etc. will be uppercase.

    Using a StringBuilder

    Putting all this together plus using a StringBuilder to avoid creating many temporary Strings would be:

    static String capitalizeString(String x) {
        StringBuilder completedConversion = new StringBuilder();
    
        for (int i = 0; i < x.length(); i++) {
            if (i == 0) {
                char ch = x.charAt(i);
                ch = Character.toUpperCase(ch);
                completedConversion.append(ch);
                i++;
            }
    
            if (!Character.isWhitespace(x.charAt(i - 1))) {
                char ch = x.charAt(i);
                completedConversion.append(ch);
            } else {
                char ch = x.charAt(i);
                ch = Character.toUpperCase(ch);
                completedConversion.append(ch);
            }
    
        }
    
        return completedConversion.toString();
    }