Java 문자열을 모든 대문자 (밑줄로 분리 된 단어)에서 CamelCase (단어 구분 기호 없음)로 변환하는 가장 간단한 방법은 무엇입니까?


152

제목은 거의 모든 것을 말합니다. Java "THIS_IS_AN_EXAMPLE_STRING"에서 형식에서 " ThisIsAnExampleString" 형식 으로 문자열을 변환 할 수있는 가장 단순하고 가장 우아한 방법은 무엇입니까? 나는 String.replaceAll()정규식을 사용하여 적어도 하나의 방법이 있어야한다고 생각합니다 .

내 생각은 다음과 같습니다. 문자열에 밑줄 ( _)을 붙이고 전체 문자열을 소문자로 변환 한 다음 replaceAll을 사용하여 밑줄이 앞에 오는 모든 문자를 대문자 버전으로 변환하십시오.


12
편집자 주 : 2015-03 : 위의 "초기 생각"은 매우 바보입니다. 6 년 만에 소프트웨어를 구축하는 방법에 대해 많이 배웁니다.
Matt Ball

4
'이 바보가 무엇을 썼는지'물어보고 그 젊고 어리석은 것을 찾기 위해 소스 컨트롤을 살펴 보는 순간. 거기에 있었어요.
pierus December

@ MatBall : 초기 생각 버전을 좋아합니다. 라이브러리는 필요 없으며 문자열 연결과 두 개의 정규식 교체 만 필요합니다.
Konrad Höffner 2016 년

답변:


192

또 다른 옵션은 Google Guava를 사용하는 것입니다. com.google.common.base.CaseFormat

George Hawkins 는이 사용 예에 ​​대해 설명을 남겼습니다.

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

3
예를 들어 George Hawkins [user : 245602]의 의견을 참조하십시오. stackoverflow.com/questions/1143951/…
Michael Scheper

5
Android 용으로 개발할 때 순수한 Java 답변이 누락되었습니다.
eliocs

1
이 답변은 나에게 가장 유용합니다. 내 자신의 코드를 잘 작성할 수는 있지만 다른 사람이 이미 가지고 있다면 분명히 바퀴를 재발 명하고 싶지 않습니다.
James Dunn


1
@ CléssioMendes github.com/google/guava/issues에서 이것을 가져 오는 것을 고려 습니까?
Arnout Engelen

128

Apache Commons lang 라이브러리 에서 WordUtils를 살펴보십시오 .

특히 capitalizeFully (String str, char [] delimiters) 메소드는 다음 작업을 수행해야합니다.

String blah = "LORD_OF_THE_RINGS";
assertEquals("LordOfTheRings", WordUtils.capitalizeFully(blah, new char[]{'_'}).replaceAll("_", ""));

그린 바!


55
아닙니다! 우리는 적절한 프로그래머이기 때문에 이미 작동하고있는 기존 유틸리티를 다시 작성해야합니다!
skaffman

24
금요일 오후 16:42입니다. 나는 다른 사람들이 그것을 다시 쓰도록 할 것이다. 나는 맥주를 위해 외출 할 것이다. \ o /;)
Dan Gravell

1
요컨대, 현재 설정으로 특정 패키지에 액세스 할 수도 없으며 capitalizeFully 메소드 이외의 것을 필요로하지 않기 때문에 직접 작성하여 아무것도 잃지 않습니다.
매트 볼

7
나는 당신의 결정 매트를 존중합니다. 아마 당신의 입장에서해야 할 것이 옳습니다. 그러나 다음 사항을 고려하십시오. * 팀의 다른 직원이 편지 대소 문자를 바꾸는 일과가 필요하다고 결정합니다. 그들은 그것을 구현합니다. 이제 ~ 20 줄을 유지 보수해야합니다. 라이브러리를 사용하면 ~ 2가됩니다. 그리고 단위 테스트를 잊지 마십시오! * 허용되는 답변에는 메소드 이름이 코드의 기능을 설명하지 않는다는 단점이 있습니다. 커먼즈와 같은 잘 재사용되는 API에는 거의 단점이 없습니다. 요점은 유지 관리가 가장 큰 소프트웨어 비용이라는 점입니다. 일반적으로 재사용은 좋은 생각입니다.
Dan Gravell

2
"이 특정 패키지에 액세스하려면" repo1.maven.org/maven2/commons-lang/commons-lang/2.5/… 를 클래스 경로에 놓으 십시오. Maven 아티팩트는 commons-lang : commons-lang : 2.5 이며 Maven Central에서 쉽게 구할 수 있습니다.
Hendy Irawan

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

참고 : 인수 유효성 검사를 추가해야합니다.


1
좋은 대답이지만 메소드 이름에 문자열이 분리되었거나 로직이 외부화되었다는 사실이 설명되어 있고 메소드 호출이 파이프로 정렬 된 경우 (예 : "THIS_IS_AN_EXAMPLE_STRING".removeUnderscores (). toCamelCase () 더 재사용이 가능합니다.
Dan Gravell

1
반드시 더 나은 것은 아닙니다 (그렇지만 재사용 가능합니다). 형식 지정 규칙에 관해서는, 낙타 수는 밑줄을 사용하지 않음을 의미합니다. 동전의 뒷면에는 밑줄 사용을 지정하는 규칙이 있습니다. 내 마음에 이것은 하나의 형식에서 다른 형식으로 변환하는 방법 일뿐입니다.
매트 볼

58
Google 구아바 라이브러리에는 공통 규칙 간 변환을위한보다 일반적인 유틸리티 열거 형이 있습니다. 이 경우에는 할 것 String result = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");입니다. com.google.common.base.CaseFormat javadoc을 참조하십시오 .
George Hawkins

1
이 답변은 터키어와 같은 로케일에서 사용될 때 문제가 발생합니다 ... 코드가 여러 로케일에서 사용되는 경우 기본 로케일에 의존하지 않는 toUpperCase (Locale) 및 toLowercase (Locale)를 사용하십시오.
vkraemer

2
@DanGravell : 밑줄을 제거한 후에는 더 이상 단어를 구별 할 수 없습니다.
njzk2

18

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"

2
변수 이름의 경우 이름은 소문자로 시작해야하므로 유효하지 않습니다.
Seby

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

3
s.length 테스트 불필요
njzk2

9

다음은 도움이 될 수있는 코드 스 니펫입니다.

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 (뱀 사례)도 처리 할 수 ​​있습니다. 허용되는 경우 수정을 제안했습니다.
sud007

6

스트림을 사용하는 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가됩니다.
mrswadge 2016 년

text.matches( "([a-z]+[a-zA-Z0-9]+)+" )낙타 케이싱 전을 사용한 테스트 는 아마도 케이싱 문제에 대한 합리적인 해결 방법 일 것입니다.
mrswadge 2016 년

2

확실하지는 않지만 char-by-char로 메모리를 적게 사용하고 신뢰할 수있는 성능을 얻을 수 있다고 생각합니다. 나는 비슷한 것을하고 있지만 백그라운드 스레드에서 루프를 처리하고 있으므로 지금 시도하고 있습니다. 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 ..."와 같은 경우에는 대량 복사의 효율성이 떨어지고 긴 문자열의 경우 입력 문자열보다 많은 메모리를 사용합니다.

문자를 통한 반복은 정식 사례가 없습니다. 그래서 나에게 불필요한 정규 표현식과 배열의 오버 헤드는 일반적으로 바람직하지 않습니다 (가능한 대량 복사 효율성을 포기 함). 의견 / 수정에 관심이 있습니다. 감사합니다.


2
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

@leorleor Iteration = 1000000000 WithChars : start = 1387547394726 end = 1387547889896 diff = 495170 Withregex : start = 1387547889897 end = 1387548944739 diff = 1054842
Srisa

1

org.modeshape.common.text.Inflector 를 사용할 수 있습니다 .

구체적으로 특별히:

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

기본적으로이 방법은 문자열을 UpperCamelCase로 변환합니다.

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


1

당신은 또한 이것을 시도 할 수 있습니다 :

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

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

1
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로 변환하는 가장 간단한 프로그램입니다. 그것이 당신을 도울 수 있기를 바랍니다 ..


0

Enum Constant낙타 케이스 로 변환 됩니다. 그러한 funtionality를 찾는 사람에게 도움이 될 것입니다.

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

0

이에 대한 또 다른 해결책은 다음과 같습니다.

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

0
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)

실행 시간 : 14ms


0

간단한 스 니펫 :

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

-2

여러 문자열에 대한 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) + ", "));

1
중복 답변
Mark Jeronimus

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

    }

1
CaseFormat표준 API가 아닙니다. 구아바라면 답이 중복됩니다.
Mark Jeronimus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.