问题描述
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();
}
使用此策略和此代码作为指导,以它为基础并实施您自己的方法。
,将问题拆分为较小的问题是一种很好的做法。所以我建议通过在“.”处拆分文本来处理句子。并遍历句子。
然后通过在“ ”处拆分句子来处理每个句子的单词。
然后检查每个单词,如果它完全是大写字母。如果是这样,保持不变。 如果不是,请检查它是否是名词,这里的意思是,它的第一个字母大写,其他字母没有大写。如果是,则保持不变,否则将其完全转换为小写。
然后(作为最后一步)将每个句子的第一个单词的第一个字母大写。
这样你就不需要任何全局标志。而且您可以轻松测试您的算法 - 用于单词和特殊情况,例如句子的开头。如果需要将其他字符添加为“.”用于将文本分成句子 - 简单。 如果您想对其他情况下的单词进行特殊处理 - 简单..