如何将字符串中每个单词的首字母大写

470

Java中是否有内置函数可以将字符串中每个单词的首字母大写,而不影响其它字母呢?

示例:

  • jon skeet -> Jon Skeet
  • miles o'Brien -> Miles O'Brien(B保持大写,这不是Title Case)
  • old mcdonald -> Old Mcdonald*

*(Old McDonald也可以,但我不指望它那么聪明。)

快速浏览Java String Documentation只显示了toUpperCase()toLowerCase()两个方法,当然它们没有提供所需的行为。自然地,谷歌搜索结果主要是这两个函数。看起来像是一个已经被发明出来的轮子,所以问一下也无妨,这样我将来可以使用它。


21
old mcdonald 应该改为 Old McDonald - Bart Kiers
2
我不指望这个函数那么聪明。(不过如果你有的话,我很乐意看看。)只需将空格后的第一个字母大写,但忽略其余部分。 - WillfulWizard
1
无论如何,你都找不到一个正确处理姓名大小写的算法......只要有一对名字,其中任何一个都可能是针对某个人的正确名称,如MacDonald和Macdonald,函数将无法知道哪个是正确的。做你所做的事情更好,尽管仍会有一些错误的姓名(比如von Neumann)。 - Dave DuPlantis
请尝试汉堡王... - Magno C
还有相关内容:https://stackoverflow.com/questions/22230306/capitalizing-hyphenated-names/54253456#54253456 - Christophe Roussy
显示剩余2条评论
52个回答

795

5
我想你的意思是 WordUtils.capitalize(str)。有关详细信息,请参阅API。 - Hans Doggen
90
保持我的哲学,总是投票支持提到公共库的答案。 - Ravi Wallau
11
要将单词中除首字母外的所有字母转换为小写,可以使用 capitalizeFully(str)。 - Umesh Rajbhandari
6
这个解决方案真的正确吗?我认为不是!如果你想将"LAMborghini"首字母大写,最终应该得到的是"Lamborghini"。因此,使用"WordUtils.capitalizeFully(str)"才是解决方案。 - basZero
7
请注意,WordUtils现已被弃用,并成为Apache Commons Text库的一部分 - https://commons.apache.org/proper/commons-text/。 - Matt W
显示剩余13条评论

234

如果你只关心第一个单词的第一个字母是否大写:

private String capitalize(final String line) {
   return Character.toUpperCase(line.charAt(0)) + line.substring(1);
}

4
这只改变了第一个单词的第一个字母。 - Christian Loncle
31
确实,这正是我的意图。 - Nick Bolton
22
但它明确忽略了问题的意图,并且对于那个例子中提供的情况失效了,几乎没有为以前给出的答案增加任何内容! - David Manheim
20
这段代码不具备崩溃安全性!想象一下 line 为 null 或长度小于2。 - stk
2
仍然,返回Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase() - Exceptyon
显示剩余3条评论

86
下面的方法将所有字母转换为大写或小写,取决于它们在空格或其他特殊字符附近的位置。
public static String capitalizeString(String string) {
  char[] chars = string.toLowerCase().toCharArray();
  boolean found = false;
  for (int i = 0; i < chars.length; i++) {
    if (!found && Character.isLetter(chars[i])) {
      chars[i] = Character.toUpperCase(chars[i]);
      found = true;
    } else if (Character.isWhitespace(chars[i]) || chars[i]=='.' || chars[i]=='\'') { // You can add other chars here
      found = false;
    }
  }
  return String.valueOf(chars);
}

我会改进和简化循环条件:if(Character.isLetter(chars[i])) { if(!found) { chars[i] = Character.toUpperCase(chars[i]); } found = true; } else { found = false; } - bancer
@bancer,通过你的示例,你无法控制哪些字符不会被大写字母跟随。 - True Soft
@TrueSoft,我不明白你的意思。为什么需要控制大写字母后面跟着什么字符?据我理解,重要的是前一个字符不是字母,而我的示例确保了这一点。只需用我的if-else块替换你的if-else-if块并运行测试即可。 - bancer
@TrueSoft,为了清晰起见,我会将“found”重命名为“previousCharIsLetter”。 - bancer
18
我喜欢那些不使用常用库的答案,因为偶尔你可能无法使用它。 - Heckman
显示剩余3条评论

48
尝试这个非常简单的方法
例如:givenString="ram is good boy"
public static String toTitleCase(String givenString) {
    String[] arr = givenString.split(" ");
    StringBuffer sb = new StringBuffer();

    for (int i = 0; i < arr.length; i++) {
        sb.append(Character.toUpperCase(arr[i].charAt(0)))
            .append(arr[i].substring(1)).append(" ");
    }          
    return sb.toString().trim();
}  

输出将为:Ram是好孩子


1
这段代码导致我们的服务器崩溃:java.lang.StringIndexOutOfBoundsException: String index out of range: 0 - Christian Loncle
40
@Chrizzz不要提交你没有测试过的代码... 如果你提供一个空字符串,它会崩溃。这是你的问题,不是Neelam的。 - Reinherd
1
如果字符串末尾有空格,那么会导致程序崩溃。因此我先使用了trim()函数去除空格,然后再用空格分割字符串。这样就可以完美地解决问题了。 - Hanuman
如果有人正在寻找Kotlin版本,这里是链接:https://dev59.com/TXI-5IYBdhLWcg3wW3Gp#55390188 - Bugs Happen

21

我使用Java 8编写了一种解决方案,我认为它更易读。

public String firstLetterCapitalWithSingleSpace(final String words) {
    return Stream.of(words.trim().split("\\s"))
    .filter(word -> word.length() > 0)
    .map(word -> word.substring(0, 1).toUpperCase() + word.substring(1))
    .collect(Collectors.joining(" "));
}

这个解决方案的要点可以在此处找到:https://gist.github.com/Hylke1982/166a792313c5e2df9d31


17
String toBeCapped = "i want this sentence capitalized";

String[] tokens = toBeCapped.split("\\s");
toBeCapped = "";

for(int i = 0; i < tokens.length; i++){
    char capLetter = Character.toUpperCase(tokens[i].charAt(0));
    toBeCapped +=  " " + capLetter + tokens[i].substring(1);
}
toBeCapped = toBeCapped.trim();

1
嗯,我认为for循环中的第二行应该是:toBeCapped += " " + capLetter + tokens[i].substring(1, tokens[i].length()); - jengelsma
2
但是这个解决方案会在开头添加一个空格。因此,您可能需要进行左修剪。 - Kamalakannan J

16
我已经编写了一个小类来将字符串中的所有单词大写。可选的多个分隔符,每个分隔符都有其自己的行为(在之前、之后或两者都大写),以处理像 O'Brian 这样的情况;可选的语言环境;不会因为代理对而中断。输出:LIVE DEMO
====================================
 SIMPLE USAGE
====================================
Source: cApItAlIzE this string after WHITE SPACES
Output: Capitalize This String After White Spaces

====================================
 SINGLE CUSTOM-DELIMITER USAGE
====================================
Source: capitalize this string ONLY before'and''after'''APEX
Output: Capitalize this string only beforE'AnD''AfteR'''Apex

====================================
 MULTIPLE CUSTOM-DELIMITER USAGE
====================================
Source: capitalize this string AFTER SPACES, BEFORE'APEX, and #AFTER AND BEFORE# NUMBER SIGN (#)
Output: Capitalize This String After Spaces, BeforE'apex, And #After And BeforE# Number Sign (#)

====================================
 SIMPLE USAGE WITH CUSTOM LOCALE
====================================
Source: Uniforming the first and last vowels (different kind of 'i's) of the Turkish word D[İ]YARBAK[I]R (DİYARBAKIR) 
Output: Uniforming The First And Last Vowels (different Kind Of 'i's) Of The Turkish Word D[i]yarbak[i]r (diyarbakir) 

====================================
 SIMPLE USAGE WITH A SURROGATE PAIR 
====================================
Source: ab c de à
Output: Ab c De À
注意:第一个字母将始终大写(如果不想要,请编辑源代码)。
请分享您的评论,帮助我找到错误或改进代码……
代码:
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class WordsCapitalizer {

    public static String capitalizeEveryWord(String source) {
        return capitalizeEveryWord(source,null,null);
    }

    public static String capitalizeEveryWord(String source, Locale locale) {
        return capitalizeEveryWord(source,null,locale);
    }

    public static String capitalizeEveryWord(String source, List<Delimiter> delimiters, Locale locale) {
        char[] chars; 

        if (delimiters == null || delimiters.size() == 0)
            delimiters = getDefaultDelimiters();                

        // If Locale specified, i18n toLowerCase is executed, to handle specific behaviors (eg. Turkish dotted and dotless 'i')
        if (locale!=null)
            chars = source.toLowerCase(locale).toCharArray();
        else 
            chars = source.toLowerCase().toCharArray();

        // First charachter ALWAYS capitalized, if it is a Letter.
        if (chars.length>0 && Character.isLetter(chars[0]) && !isSurrogate(chars[0])){
            chars[0] = Character.toUpperCase(chars[0]);
        }

        for (int i = 0; i < chars.length; i++) {
            if (!isSurrogate(chars[i]) && !Character.isLetter(chars[i])) {
                // Current char is not a Letter; gonna check if it is a delimitrer.
                for (Delimiter delimiter : delimiters){
                    if (delimiter.getDelimiter()==chars[i]){
                        // Delimiter found, applying rules...                       
                        if (delimiter.capitalizeBefore() && i>0 
                            && Character.isLetter(chars[i-1]) && !isSurrogate(chars[i-1]))
                        {   // previous character is a Letter and I have to capitalize it
                            chars[i-1] = Character.toUpperCase(chars[i-1]);
                        }
                        if (delimiter.capitalizeAfter() && i<chars.length-1 
                            && Character.isLetter(chars[i+1]) && !isSurrogate(chars[i+1]))
                        {   // next character is a Letter and I have to capitalize it
                            chars[i+1] = Character.toUpperCase(chars[i+1]);
                        }
                        break;
                    }
                } 
            }
        }
        return String.valueOf(chars);
    }


    private static boolean isSurrogate(char chr){
        // Check if the current character is part of an UTF-16 Surrogate Pair.  
        // Note: not validating the pair, just used to bypass (any found part of) it.
        return (Character.isHighSurrogate(chr) || Character.isLowSurrogate(chr));
    }       

    private static List<Delimiter> getDefaultDelimiters(){
        // If no delimiter specified, "Capitalize after space" rule is set by default. 
        List<Delimiter> delimiters = new ArrayList<Delimiter>();
        delimiters.add(new Delimiter(Behavior.CAPITALIZE_AFTER_MARKER, ' '));
        return delimiters;
    } 

    public static class Delimiter {
        private Behavior behavior;
        private char delimiter;

        public Delimiter(Behavior behavior, char delimiter) {
            super();
            this.behavior = behavior;
            this.delimiter = delimiter;
        }

        public boolean capitalizeBefore(){
            return (behavior.equals(Behavior.CAPITALIZE_BEFORE_MARKER)
                    || behavior.equals(Behavior.CAPITALIZE_BEFORE_AND_AFTER_MARKER));
        }

        public boolean capitalizeAfter(){
            return (behavior.equals(Behavior.CAPITALIZE_AFTER_MARKER)
                    || behavior.equals(Behavior.CAPITALIZE_BEFORE_AND_AFTER_MARKER));
        }

        public char getDelimiter() {
            return delimiter;
        }
    }

    public static enum Behavior {
        CAPITALIZE_AFTER_MARKER(0),
        CAPITALIZE_BEFORE_MARKER(1),
        CAPITALIZE_BEFORE_AND_AFTER_MARKER(2);                      

        private int value;          

        private Behavior(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }           
    } 

10

使用org.apache.commons.lang.StringUtils让它变得非常简单。

capitalizeStr = StringUtils.capitalize(str);

2
@Ash StringUtils.capitalise(str)已被弃用。请参见:https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html#capitalise(java.lang.String) - Navigatron
这只将字符串的第一个字符大写,而不是将字符串中每个单词的第一个字符大写。WordUtils之所以被弃用,仅仅是因为它已经从commons lang移动到了commons text https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/WordUtils.html#capitalizeFully-java.lang.String- - opticyclic

9

自Java 9以后

您可以像下面这样使用String::replaceAll

public static void upperCaseAllFirstCharacter(String text) {
    String regex = "\\b(.)(.*?)\\b";
    String result = Pattern.compile(regex).matcher(text).replaceAll(
            matche -> matche.group(1).toUpperCase() + matche.group(2)
    );

    System.out.println(result);
}

例子:

upperCaseAllFirstCharacter("hello this is Just a test");

输出

Hello This Is Just A Test

7

通过这段简单的代码

String example="hello";

example=example.substring(0,1).toUpperCase()+example.substring(1, example.length());

System.out.println(example);

结果: 你好


6
关于“HELLO”,它返回的是“HELLO”,但预期的是“Hello”,因此您应该在第二个子字符串中使用toLowerCase()。 - Trikaldarshiii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接