سؤال

I have a method that converts all the first letters of the words in a sentence into uppercase.

public static String toTitleCase(String s)
{
    String result = "";
    String[] words = s.split(" ");

    for (int i = 0; i < words.length; i++) 
    {
        result += words[i].replace(words[i].charAt(0)+"", Character.toUpperCase(words[i].charAt(0))+"") + " ";
    }

    return result;
}

The problem is that the method converts each other letter in a word that is the same letter as the first to uppercase. For example, the string title comes out as TiTle

For the input this is a title this becomes the output This Is A TiTle

I've tried lots of things. A nested loop that checks every letter in each word, and if there is a recurrence, the second is ignored. I used counters, booleans, etc. Nothing works and I keep getting the same result.

What can I do? I only want the first letter in upper case.

هل كانت مفيدة؟

المحلول

Instead of using the replace() method, try replaceFirst().

result += words[i].replaceFirst(words[i].charAt(0)+"", Character.toUpperCase(words[i].charAt(0))+"") + " ";

Will output:

This Is A Title 

نصائح أخرى

The problem is that you are using replace method which replaces all occurrences of described character. To solve this problem you can either

  • use replaceFirst instead
    1. take first letter,
    2. create its uppercase version
    3. concatenate it with rest of string which can be created with a little help of substring method.
  • since you are using replace(String, String) which uses regex you can add ^ before character you want to replace like replace("^a","A"). ^ means start of input so it will only replace a that is placed after start of input.

I would probably use second approach.


Also currently in each loop your code creates new StringBuilder with data stored in result, append new word to it, and reassigns result of output from toString().
This is infective approach. Instead you should create StringBuilder before loop that will represent your result and append new words created inside loop to it and after loop ends you can get its String version with toString() method.

Doing some Regex-Magic can simplify your task:

public static void main(String[] args) {
  final String test = "this is a Test";

  final StringBuffer buffer = new StringBuffer(test);
  final Pattern patter = Pattern.compile("\\b(\\p{javaLowerCase})");
  final Matcher matcher = patter.matcher(buffer);
  while (matcher.find()) {
    buffer.replace(matcher.start(), matcher.end(), matcher.group().toUpperCase());
  }

  System.out.println(buffer);
}

The expression \\b(\\p{javaLowerCase}) matches "The beginning of a word followed by a lower-case letter", while matcher.group() is equal to whats inside the () in the part that matches. Example: Applying on "test" matches on "t", so start is 0, end is 1 and group is "t". This can easily run through even a huge amount of text and replace all those letters that need replacement.

In addition: it is always a good idea to use a StringBuffer (or similar) for String manipulation, because each String in Java is unique. That is if you do something like result += stringPart you actually create a new String (equal to result + stringPart) each time this is called. So if you do this with like 10 parts, you will in the end have at least 10 different Strings in memory, while you only need one, which is the final one.

StringBuffer instead uses something like char[] to ensure that if you change only a single character no extra memory needs to be allocated.

Note that a patter only need to be compiled once, so you can keep that as a class variable somewhere.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top