将 Java 字符串从全部大写(由下划线分隔的单词)转换为 CamelCase(无单词分隔符)的最简单方法是啥?

Posted

技术标签:

【中文标题】将 Java 字符串从全部大写(由下划线分隔的单词)转换为 CamelCase(无单词分隔符)的最简单方法是啥?【英文标题】:What is the simplest way to convert a Java string from all caps (words separated by underscores) to CamelCase (no word separators)?将 Java 字符串从全部大写(由下划线分隔的单词)转换为 CamelCase(无单词分隔符)的最简单方法是什么? 【发布时间】:2010-11-11 18:02:38 【问题描述】:

标题几乎说明了一切。我可以在 Java 中将字符串从 "THIS_IS_AN_EXAMPLE_STRING" 格式转换为“ThisIsAnExampleString”格式的最简单/最优雅的方法是什么?我认为至少有一种方法可以使用String.replaceAll() 和正则表达式。

我最初的想法是:在字符串前面加上下划线 (_),将整个字符串转换为小写,然后使用 replaceAll 将每个前面带有下划线的字符转换为大写版本。

【问题讨论】:

编者注,2015-03:上面的“初步想法”非常愚蠢。您在六年内学到了很多关于构建软件的知识。 当你问'这是什么白痴写的'并查看源代码控制以发现你所做的那个年轻、愚蠢的那一刻。去过那里,做到了。 @MattBall:我喜欢最初的想法版本,它不需要库,只需要一个字符串连接和两个正则表达式替换。 【参考方案1】:

另一种选择是使用 Google Guava 的 com.google.common.base.CaseFormat

George Hawkins 对此使用示例发表了评论:

CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");

【讨论】:

请参阅 George Hawkins [user:245602] 的评论作为示例。 ***.com/questions/1143951/… 在为 android 开发时,我想念纯 Java 的答案。 这个答案对我最有用。我可以很好地编写自己的代码,但如果其他人已经有了,我当然不想重新发明***。 也可以参考***.com/questions/10310321/… @CléssioMendes 你有没有考虑在github.com/google/guava/issues 提出这个问题?【参考方案2】:

看看WordUtils in the Apache Commons lang库:

具体来说,capitalizeFully(String str, char[] delimiters) 方法应该可以完成这项工作:

String blah = "LORD_OF_THE_RINGS";
assertEquals("LordOfTheRings", WordUtils.capitalizeFully(blah, '_').replaceAll("_", ""));

绿条!

【讨论】:

不,先生!我们应该自己重写这些现有的、已经运行的实用程序,因为我们是合适的程序员 周五下午 16:42。我会让其他人重写它,我要去喝啤酒\o/;) 更重要的是,我什至无法使用我当前的设置访问那个特定的包,而且由于我真的(还)不需要任何超出 capitalizeFully 方法的东西,所以我没有任何损失自己写。 我尊重你的决定,马特,在你的位置上做这件事可能是正确的。但是,请考虑以下事项: * 您团队中的其他人决定他们需要一个例程来交换字母的大小写。他们实施它。您现在有大约 20 行需要维护。如果您使用该库,您将拥有 ~2。并且不要忘记单元测试! * 接受的答案有一个缺点,即方法名称没有描述代码的作用。像公共资源这样重用良好的 API 很少有这些缺点。关键是维护是软件最大的成本。一般来说,重复使用是个好主意。 要“访问这个特定的包”,将repo1.maven.org/maven2/commons-lang/commons-lang/2.5/… 放到你的类路径中。 Maven 工件是 commons-lang:commons-lang:2.5,可从 Maven Central 轻松获得。【参考方案3】:
static String toCamelCase(String s)
   String[] parts = s.split("_");
   String camelCaseString = "";
   for (String part : parts)
      camelCaseString = camelCaseString + toProperCase(part);
   
   return camelCaseString;


static String toProperCase(String s) 
    return s.substring(0, 1).toUpperCase() +
               s.substring(1).toLowerCase();

注意:您需要添加参数验证。

【讨论】:

不错的答案,但是如果方法名称描述字符串被拆分或逻辑被外部化并且方法调用对齐为管道的事实会更好一些,例如"THIS_IS_AN_EXAMPLE_STRING".removeUnderscores().toCamelCase() 这更可重用。 这不一定更好(虽然是的,它更可重用)。当涉及到名称格式约定时,camelcase 可以/确实暗示不使用下划线;在硬币的反面,有一些约定使用下划线。所以在我看来,这只是一种从一种格式转换为另一种格式的方法。 Google guava 库有一个更通用的实用程序枚举,用于在常用约定之间进行转换。对于这种情况,您可以使用String result = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");。见com.google.common.base.CaseFormat javadoc。 此答案在土耳其语等语言环境中使用时会遇到问题...如果您的代码要在多个语言环境中使用,请使用 toUpperCase(Locale) 和 toLowercase(Locale).. 不是那些这取决于默认语言环境。 @DanGravell : 删除下划线后,就无法区分单词了。【参考方案4】:

使用 Apache Commons Lang3 lib 非常简单。

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;

public String getName(String text) 
  return StringUtils.remove(WordUtils.capitalizeFully(text, '_'), "_");

例子:

getName("SOME_CONSTANT");

给予:

"SomeConstant"

【讨论】:

在变量名的情况下,这是无效的,因为名称必须以小写开头。【参考方案5】:

这是一个可能有帮助的代码 sn-p:

String input = "ABC_DEF";
StringBuilder sb = new StringBuilder();
for( String oneString : input.toLowerCase().split("_") )

    sb.append( oneString.substring(0,1).toUpperCase() );
    sb.append( oneString.substring(1) );


// sb now holds your desired String

【讨论】:

此解决方案适用于 ALL_UPPER 到 Camel 的情况。但程序稍作改动也可以处理 MixED_case 或 lower_case(蛇形大小写)。如果允许,我建议进行修改。【参考方案6】:

使用 Streams 的 Java 1.8 示例

String text = "THIS_IS_SOME_TEXT";

String bactrianCamel = Stream.of(text.split("[^a-zA-Z0-9]"))
        .map(v -> v.substring(0, 1).toUpperCase() + v.substring(1).toLowerCase())
        .collect(Collectors.joining());
String dromedaryCamel = bactrianCamel.toLowerCase().substring(0, 1) + bactrianCamel.substring(1); 

System.out.printf("%s is now %s%n", text, dromedaryCamel); 

THIS_IS_SOME_TEXT 现在是 thisIsSomeText

【讨论】:

我喜欢这个答案,但是如果输入字符串已经是驼峰式,它就有一个缺陷,在这种情况下,它会降低整个输入的大小写。例如abcDef 变成 abcdef。 在驼峰式大小写之前使用text.matches( "([a-z]+[a-zA-Z0-9]+)+" ) 进行测试可能是解决小写问题的合理解决方法。 在 map 之前添加一个过滤器对于过滤空字符串和避免空指针很有用。 Stream.of(text.split("[^a-zA-Z0-9]")).filter(x -> x.length() > 0).map(v -> v.substring(0, 1).toUpperCase() + v.substring(1).toLowerCase()) .collect(Collectors.joining());【参考方案7】:
public static void main(String[] args) 
    String start = "THIS_IS_A_TEST";
    StringBuffer sb = new StringBuffer();
    for (String s : start.split("_")) 
        sb.append(Character.toUpperCase(s.charAt(0)));
        if (s.length() > 1) 
            sb.append(s.substring(1, s.length()).toLowerCase());
        
    
    System.out.println(sb);

【讨论】:

不需要 s.length 测试【参考方案8】:

Apache Commons 项目现在确实有 CaseUtils 类,它有一个 toCamelCase 方法,完全按照 OP 的要求:

 CaseUtils.toCamelCase("THIS_IS_AN_EXAMPLE_STRING", true, '_');

【讨论】:

【参考方案9】:

您可以使用org.modeshape.common.text.Inflector。

具体来说:

String camelCase(String lowerCaseAndUnderscoredWord,
    boolean uppercaseFirstLetter, char... delimiterChars) 

默认情况下,此方法将字符串转换为大写字母。

Maven 工件是:org.modeshape:modeshape-common:2.3.0.Final

在 JBoss 存储库上:https://repository.jboss.org/nexus/content/repositories/releases

这是 JAR 文件:https://repository.jboss.org/nexus/content/repositories/releases/org/modeshape/modeshape-common/2.3.0.Final/modeshape-common-2.3.0.Final.jar

【讨论】:

【参考方案10】:

不确定,但我认为我可以通过逐个字符来使用更少的内存并获得可靠的性能。我正在做类似的事情,但在后台线程的循环中,所以我现在正在尝试这个。我有一些经验,String.split 比预期的要贵。而且我正在开发 Android 并希望 GC 打嗝比 CPU 使用更重要。

  public static String toCamelCase(String value) 
    StringBuilder sb = new StringBuilder();

    final char delimChar = '_';
    boolean lower = false;
    for (int charInd = 0; charInd < value.length(); ++charInd) 
      final char valueChar = value.charAt(charInd);
      if (valueChar == delimChar) 
        lower = false;
       else if (lower) 
        sb.append(Character.toLowerCase(valueChar));
       else 
        sb.append(Character.toUpperCase(valueChar));
        lower = true;
      
    

    return sb.toString();
  

String.split 昂贵的一个提示是它的输入是一个正则表达式(不是像 String.indexOf 这样的字符)并且它返回一个数组(而不是说一个迭代器,因为循环一次只使用一个东西)。像“AB_AB_AB_AB_AB_AB...”这样的情况会破坏任何批量复制的效率,并且对于长字符串,使用的内存比输入字符串多一个数量级。

而循环遍历字符没有规范的情况。所以对我来说,不需要的正则表达式和数组的开销似乎通常不太可取(然后放弃可能的批量复制效率)。有兴趣听取意见/更正,谢谢。

【讨论】:

【参考方案11】:
public String withChars(String inputa) 
    String input = inputa.toLowerCase();
    StringBuilder sb = new StringBuilder();
    final char delim = '_';
    char value;
    boolean capitalize = false;
    for (int i=0; i<input.length(); ++i) 
        value = input.charAt(i);
        if (value == delim) 
            capitalize = true;
        
        else if (capitalize) 
            sb.append(Character.toUpperCase(value));
            capitalize = false;
        
        else 
            sb.append(value);
        
    

    return sb.toString();


public String withRegex(String inputa) 
    String input = inputa.toLowerCase();
    String[] parts = input.split("_");
    StringBuilder sb = new StringBuilder();
    sb.append(parts[0]);
    for (int i=1; i<parts.length; ++i) 
        sb.append(parts[i].substring(0,1).toUpperCase());
        sb.append(parts[i].substring(1));
    

    return sb.toString();

时间:以毫秒为单位。

Iterations = 1000
WithChars: start = 1379685214671 end = 1379685214683 diff = 12
WithRegex: start = 1379685214683 end = 1379685214712 diff = 29

Iterations = 1000
WithChars: start = 1379685217033 end = 1379685217045 diff = 12
WithRegex: start = 1379685217045 end = 1379685217077 diff = 32

Iterations = 1000
WithChars: start = 1379685218643 end = 1379685218654 diff = 11
WithRegex: start = 1379685218655 end = 1379685218684 diff = 29

Iterations = 1000000
WithChars: start = 1379685232767 end = 1379685232968 diff = 201
WithRegex: start = 1379685232968 end = 1379685233649 diff = 681

Iterations = 1000000
WithChars: start = 1379685237220 end = 1379685237419 diff = 199
WithRegex: start = 1379685237419 end = 1379685238088 diff = 669

Iterations = 1000000
WithChars: start = 1379685239690 end = 1379685239889 diff = 199
WithRegex: start = 1379685239890 end = 1379685240585 diff = 695

Iterations = 1000000000
WithChars: start = 1379685267523 end = 1379685397604 diff = 130081
WithRegex: start = 1379685397605 end = 1379685850582 diff = 452977

【讨论】:

酷,是用输入“THIS_IS_AN_EXAMPLE_STRING”进行迭代吗? @leorleor Iteration = 1000000000 WithChars: start = 1387547394726 end = 1387547889896 diff = 495170 WithRegex: start = 1387547889897 end = 1387548944739 diff = 1054842 【参考方案12】:

你也可以试试这个:

 public static String convertToNameCase(String s)
    
        if (s != null)
        
            StringBuilder b = new StringBuilder();
            String[] split = s.split(" ");
            for (String srt : split)
            
                if (srt.length() > 0)
                
                    b.append(srt.substring(0, 1).toUpperCase()).append(srt.substring(1).toLowerCase()).append(" ");
                
            
            return b.toString().trim();
        
        return s;
    

【讨论】:

【参考方案13】:
protected String toCamelCase(String input) 
    if (input == null) 
        return null;
    

    if (input.length() == 0) 
        return "";
    

    // lowercase the first character
    String camelCaseStr = input.substring(0, 1).toLowerCase();

    if (input.length() > 1) 
        boolean isStartOfWord = false;

        for (int i = 1; i < input.length(); i++) 
            char currChar = input.charAt(i);
            if (currChar == '_') 
                // new word. ignore underscore
                isStartOfWord = true;
             else if (Character.isUpperCase(currChar)) 
                // capital letter. if start of word, keep it
                if (isStartOfWord) 
                    camelCaseStr += currChar;
                 else 
                    camelCaseStr += Character.toLowerCase(currChar);
                
                isStartOfWord = false;
             else 
                camelCaseStr += currChar;
                isStartOfWord = false;
            
        
    

    return camelCaseStr;

【讨论】:

【参考方案14】:
public String CamelCase(String str)

    String CamelCase="";
    String parts[] = str.split("_");
    for(String part:parts)
    
        String as=part.toLowerCase();
        int a=as.length();
        CamelCase = CamelCase + as.substring(0, 1).toUpperCase()+ as.substring(1,a);    
    
    return CamelCase;

这是转换为 CamelCase 的最简单的程序。 希望对你有帮助..

【讨论】:

【参考方案15】:
public static String toCamelCase(String value) 
    value = value.replace("_", " ");
    String[] parts = value.split(" ");
    int i = 0;
    String camelCaseString = "";
    for (String part : parts) 
        if (part != null && !part.isEmpty()) 
            if (i == 0) 
                camelCaseString = part.toLowerCase();
             else if (i > 0 && part.length() > 1) 
                String oldFirstChar = part.substring(0, 1);
                camelCaseString = camelCaseString + part.replaceFirst(oldFirstChar, oldFirstChar.toUpperCase());
             else 
                camelCaseString = camelCaseString + part + " ";
            
            i++;
        
    
    return camelCaseString;


public static void main(String[] args) 
    String string = "HI_tHiS_is_SomE Statement";
    System.out.println(toCamelCase(string));

【讨论】:

【参考方案16】:

对不起,我的五分钱,我认为在 java 中的话太多了)) 我只是想知道。为什么java中的正则表达式引擎不像JS中那样熟悉lambdas((

无论如何。随着java 8+的构造出现在我的脑海中:

Arrays.stream("THIS_IS_AN_EXAMPLE_STRING".split("_"))
    .collect(StringBuilder::new,
        (result, w) -> result
            .append(w.substring(0, 1).toUpperCase())
            .append(w.substring(1).toLowerCase()),
        StringBuilder::append)
    .toString())

如果你关心内存消耗,下面的代码关心它:

"THIS_IS_AN_EXAMPLE_STRING".chars().collect(StringBuilder::new,
    (result, c) -> 
        // Detect place for deal with
        if (result.length() > 0 && result.charAt(result.length() - 1) == '_') 
            result.setCharAt(result.length() - 1,
                    Character.toUpperCase((char) c));
         else if (result.length() > 0) 
            result.append(Character.toLowerCase((char) c));
         else 
            result.append(Character.toUpperCase((char) c));
        
    , StringBuilder::append).toString()

【讨论】:

【参考方案17】:

它将Enum Constant 转换为骆驼案例。这对任何正在寻找这种功能的人都会有所帮助。

public enum TRANSLATE_LANGUAGES 
        ARABIC("ar"), BULGARIAN("bg"), CATALAN("ca"), CHINESE_SIMPLIFIED("zh-CN"), CHINESE_TRADITIONAL("zh-TW"), CZECH("cs"), DANISH("da"), DUTCH("nl"), ENGLISH("en"), ESTONIAN("et"), FINNISH("fi"), FRENCH(
                "fr"), GERMAN("de"), GREEK("el"), HAITIAN_CREOLE("ht"), HEBREW("he"), HINDI("hi"), HMONG_DAW("mww"), HUNGARIAN("hu"), INDONESIAN("id"), ITALIAN("it"), JAPANESE("ja"), KOREAN("ko"), LATVIAN(
                "lv"), LITHUANIAN("lt"), MALAY("ms"), NORWEGIAN("no"), PERSIAN("fa"), POLISH("pl"), PORTUGUESE("pt"), ROMANIAN("ro"), RUSSIAN("ru"), SLOVAK("sk"), SLOVENIAN("sl"), SPANISH("es"), SWEDISH(
                "sv"), THAI("th"), TURKISH("tr"), UKRAINIAN("uk"), URDU("ur"), VIETNAMESE("vi");

        private String code;

        TRANSLATE_LANGUAGES(String language) 
            this.code = language;
        

        public String langCode() 
            return this.code;
        

        public String toCamelCase(TRANSLATE_LANGUAGES lang) 
            String toString = lang.toString();
            if (toString.contains("_")) 
                String st = toUpperLowerCase(toString.split("_"));
            

            return "";
        

        private String toUpperLowerCase(String[] tempString) 
            StringBuilder builder = new StringBuilder();

            for (String temp : tempString) 

                String char1 = temp.substring(0, 1);
                String restString = temp.substring(1, temp.length()).toLowerCase();
                builder.append(char1).append(restString).append(" ");

            

            return builder.toString();
        
    

【讨论】:

【参考方案18】:

对此的另一种解决方案可能如下。

public static String toCamelCase(String str, String... separators) 
    String separatorsRegex = "\\".concat(org.apache.commons.lang3.StringUtils.join(separators, "|\\"));
    List splits = Arrays.asList(str.toLowerCase().split(separatorsRegex));
    String capitalizedString = (String)splits.stream().map(WordUtils::capitalize).reduce("", String::concat);
    return capitalizedString.substring(0, 1).toLowerCase() + capitalizedString.substring(1);

【讨论】:

【参考方案19】:
public static final String  UPPER_CAMEL = "initUp";
public static final String  LOWER_CAMEL = "initLow";

public String toCamel(String src, String separator, String format) 
    StringBuilder builder = new StringBuilder(src.toLowerCase());
    int len = builder.length();

    for (int idx = builder.indexOf(separator); idx > 0 && idx < len; idx = builder.indexOf(separator, idx)) 
        builder = builder.replace(idx, idx + 2, (String.valueOf(builder.charAt(idx + 1)).toUpperCase()));
    

    switch (format) 
    case LOWER_CAMEL:
        builder.setCharAt(0, Character.toLowerCase(builder.charAt(0)));
        break;
    default:
        builder.setCharAt(0, Character.toUpperCase(builder.charAt(0)));
        break;
    

    return builder.toString();


调用为

toCamel("THIS_IS_AN_EXAMPLE_STRING", "_", UPPER_CAMEL)

执行时间:14 毫秒

【讨论】:

【参考方案20】:

一个简单的片段:

 public static String camelCase(String in) 
    if (in == null || in.length() < 1)  return "";  //validate in
    String out = "";
    for (String part : in.toLowerCase().split("_")) 
        if (part.length() < 1)  //validate length
            continue;
        
        out += part.substring(0, 1).toUpperCase();
        if (part.length() > 1)  //validate length
            out += part.substring(1);
        
    
    return out;

【讨论】:

【参考方案21】:
    protected String toCamelCase(CaseFormat caseFormat, String... words)
        if (words.length  == 0)
          throw new IllegalArgumentException("Word list is empty!");
        

        String firstWord = words[0];
        String [] restOfWords = Arrays.copyOfRange(words, 1, words.length);

        StringBuffer buffer = new StringBuffer();
        buffer.append(firstWord);
        Arrays.asList(restOfWords).stream().forEach(w->buffer.append("_"+ w.toUpperCase()));

        return CaseFormat.UPPER_UNDERSCORE.to(caseFormat, buffer.toString());

    

【讨论】:

CaseFormat 不是标准 API。如果是番石榴,则重复答案。【参考方案22】:

用于多个字符串的 Java 8:

import com.google.common.base.CaseFormat;



String camelStrings = "YOUR_UPPER, YOUR_TURN, ALT_TAB";

List<String> camelList = Arrays.asList(camelStrings.split(","));
camelList.stream().forEach(i -> System.out.println(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, i) + ", "));

【讨论】:

重复答案

以上是关于将 Java 字符串从全部大写(由下划线分隔的单词)转换为 CamelCase(无单词分隔符)的最简单方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

java项目命名规范

Java命名规范

Java--命名规范

Java 命名规范

编程的命名规则

java基础学习——14代码格式