java - 如果单词完全大写,如何在保持单词大写的同时将第一个字母大写并将其余字母小写

问题描述

getSentenceCaseText()

以句子形式返回当前文本的字符串表示。判例是 在句子中使用大写字母或仅将第一个大写的传统方式 词和任何专有名词。此外,所有大写单词应保持原样。

对于这项作业,名词仅限于以一个大写字母开头的单词。

**以字符串“First SenTence.secOND sentence.tHIRD SENTENCE”为例

它的输出将是(第一句。第二句。第三句)**


这是我上面作业的代码。我可以将每个点后的第一个字母大写,并将其余字母设置为小写,但我不知道如何保持完整的大写单词。

这是我的代码如下:

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();
}
    

解决方法

由于输入的字符串可能包含多个句子,所以应该拆分成句子,然后将每个句子拆分为单词,所有大写的单词保持不变,句子中的第一个单词大写,其余单词为变成小写。

可以使用正则表达式 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());
}

测试:

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

输出:

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

您应该有一个布尔值 - isCapitalize

起初,这是真的。

在迭代文本期间,您应该使用相同的单词创建新的操作文本。

如果 isCapitalize 标志为真,则以首字母大写的方式书写单词。否则,用小写字母写。如果整个单词都有大写字母(这就是我们遍历单词的原因) - 将整个单词都用大写字母。

如果您有“.”,则该标志仅对 1 个字有效。

现在把上面的文字写成代码。 如果您需要帮助,请告诉我们。

,

您发布的大部分逻辑都可以正常工作。问题是像“SENTENCE”这样的,因为您用来检查大小写的逻辑不正确。

最大的问题是您试图遍历单词并同时检查该字符串是否大写。

最简单的方法是分离关注点;尝试事先检查 单词 是否大写,然后采取相应措施。

首先创建一个只检查单词是否大写的方法。例如:

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;
}

此方法接收一个字符串(待检查)和一个 int 值(ie, start),它告诉方法应该从字符串的哪个部分进行检查开始。

对于 getSentenceCaseText 方法,请遵循以下策略。首先检查当前单词是否大写:

 boolean capitalize = isUpper(text,pos);

如果大写,方法应该跳过这个词并移动到下一个。否则,它会将第一个字符大写并降低剩余的字符。对文本中的所有单词应用相同的逻辑。

代码可能如下所示:

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();
}

使用此策略和此代码作为指导,以它为基础并实施您自己的方法。

,

将问题拆分为较小的问题是一种很好的做法。所以我建议通过在“.”处拆分文本来处理句子。并遍历句子。

然后通过在“ ”处拆分句子来处理每个句子的单词。

然后检查每个单词,如果它完全是大写字母。如果是这样,保持不变。 如果不是,请检查它是否是名词,这里的意思是,它的第一个字母大写,其他字母没有大写。如果是,则保持不变,否则将其完全转换为小写。

然后(作为最后一步)将每个句子的第一个单词的第一个字母大写。

这样你就不需要任何全局标志。而且您可以轻松测试您的算法 - 用于单词和特殊情况,例如句子的开头。如果需要将其他字符添加为“.”用于将文本分成句子 - 简单。 如果您想对其他情况下的单词进行特殊处理 - 简单..