Jeffery
Jeffery

Reputation: 33

How to capitalize first letter and lowercase the rest while keeping the word capital if it is in fully uppercase - java

getSentenceCaseText()

return a string representation of current text in sentence case. Sentence case is the conventional way of using capital letters in a sentence or capitalizing only the first word and any proper nouns. In addition, all capital word should remain as it is.

For this assignment, noun is limited to words that have ONE capital letter at the beginning.

**As an example the string "First SenTence. secOND sentence. tHIRD SENTENCE"

its output will be (First sentence. Second sentence. Third SENTENCE)**


This is my code for the above assignment. I could capitalize the first letter after every dot and set the rest as lowercase but i couldn't find out how to keep full uppercase word as it is.

This is my code below:

public String getSentenceCaseText(String text) { 
    
    int pos = 0;
    boolean capitalize = true;
    StringBuilder sb = new StringBuilder(text);
    
    while (pos < sb.length()){
         sb.setCharAt(pos, Character.toLowerCase(sb.charAt(pos)));
         if (sb.charAt(pos) == '.') {
            capitalize = true;      
        } else if (capitalize && !Character.isWhitespace(sb.charAt(pos))) {
            sb.setCharAt(pos, Character.toUpperCase(sb.charAt(pos)));   
            capitalize = false;
        }
        pos++;
       }   
   return sb.toString();
}
    

Upvotes: 1

Views: 3300

Answers (5)

Hello world
Hello world

Reputation: 33

Set the first word as uppercase and the rest lowercase

String output = someString.substring(0, 1).toUpperCase() + someString.substring(1).toLowerCase(Locale.ROOT);

Upvotes: -1

javadev
javadev

Reputation: 790

You should have a boolean - isCapitalize.

At first, it's true.

During iterating your text, over words, you should create the new manipulated text with the same word.

If isCapitalize flag is true, write the word in a first-capital-letter manner. Else, write it in small-capital-letters. If the whole word has capital letters (that's the reason we iterate over words) - right the whole word in capital letters.

If you have ".", the flag is on for 1 word only.

Now take the above text and formulate it into code. Let us know if you need some help.

Upvotes: 1

juwil
juwil

Reputation: 466

It is good practice to split a problem in smaller ones. So I recommend to handle sentences by splitting the text at the "." and iterate over the sentences.

Then you handle the words of every sentence by splitting sentence at the " ".

Then you check for every word, if it is completely in capital letters. if so, leave unchanged. If not, you check, if it is a noun, wich here means, it has a capital first letter and no capital letters else. If so, leave it unchanged, otherwise convert it to lower case completely.

You then (as the last step) capitalize the first letter of the first word of every sentence.

This way you do not need any global flags whatsoever. And you can easily test your algorithm - for words and for special cases like beginning of a sentence. If you need to add other characters as "." for splitting the text into sentences - easy. If you want special treatment for other cases of words - easy..

Upvotes: 1

Nowhere Man
Nowhere Man

Reputation: 19545

As the input string may contain multiple sentences, it should be split into sentences, then each sentence should be split to words, the word in all caps remains the same, the first word in sentence is capitalized, and the rest words are turned lowercase.

It can be done using a regular expression to split a string along with keeping delimiters.

static String capitalizeSentence(String input) {
    if (null == input || 0 == input.length()) {
        return input;
    }

    return Arrays
        .stream(input.split("((?<=[.!\\?]\\s?)|(?=[.!\\?]\\s?))"))
        .flatMap(sent -> { 
            String[] words = sent.split("((?<=[^\\w])|(?=[^\\w]))"); 
            return 
                Stream.concat(
                    Stream.of(words[0].matches("[A-Z]+") // process first word
                        ? words[0] 
                        : (Character.toUpperCase(words[0].charAt(0)) + 
                            (words[0].length() > 1 ? words[0].substring(1).toLowerCase() : ""))
                    ),
                    // process the rest of words
                    Arrays.stream(words)
                          .skip(1)
                          .map(word -> word.matches("[A-Z]+") ? word : word.toLowerCase())
                );
        })
        .collect(Collectors.joining());
}

Test:

System.out.println(capitalizeSentence("o! HI!first  SenTence. secOND  sentence. tHIRD: SENTENCE. am I OK?! yes, I am fine!!"));

Output:

O! HI!First  sentence. Second  sentence. Third: SENTENCE. Am I OK?! Yes, I am fine!!

Upvotes: 1

dreamcrash
dreamcrash

Reputation: 51393

Most of the logic that you have posted works fine. The problem is words like "SENTENCE" because the logic that you are using to check the capitalization is incorrect.

The biggest problem is that you are trying to iterate over the words and check at the same time if that string is or not capitalize.

The easiest way is to separate concerns; try to check beforehand if the word is or not capitalized and act accordingly.

First create a method that just checks if a word is or not capitalized. For example:

public static boolean isUpper(String s, int start) {
    for(int i = start; i < s.length(); i++) {
        char c = s.charAt(i);
        if(c == '.' || c == ' ')
            return true;
        if (!Character.isUpperCase(c))
            return false;
    }
    return true;
}

This method receives a string (to be checked) and an int value (i.e., start) that tells the method from which part of the string should the checking start.

For the getSentenceCaseText method follow the following strategy. First check if the current word is capitalized:

 boolean capitalize = isUpper(text, pos);

if is capitalized the method should skip this word and move to the next one. Otherwise, it capitalizes the first character and lowers the remaining. Apply the same logic to all words in the text.

The code could look like the following:

public static String getSentenceCaseText(String text) {
    int pos = 0;
    StringBuilder sb = new StringBuilder(text);

    // Iterate over the string
    while (pos < sb.length()){
        // First check if the word is capitalized 
        boolean capitalize = isUpper(text, pos);
        char c = sb.charAt(pos);

        // Make the first letter capitalized for the cases that it was not 
        sb.setCharAt(pos, Character.toUpperCase(c));
        pos++;

        // Let us iterate over the word
        // If it is not capitalized let us lower its characters
        // otherwise just ignore and skip the characters 
        for (;pos < sb.length() && text.charAt(pos) != '.' && text.charAt(pos) != ' '; pos++)
            if(!capitalize)
                sb.setCharAt(pos, Character.toLowerCase(sb.charAt(pos)));
       
       // Finally we need to skip all the spaces
       for(; pos < sb.length() && text.charAt(pos) == ' '; pos++ );
    }

    return sb.toString();
}

Use this strategy and this code as guide, build upon it and implement your own method.

Upvotes: 1

Related Questions