Qual é a maneira mais simples de converter uma string Java de todas as maiúsculas (palavras separadas por sublinhados) em CamelCase (sem separadores de palavras)?

152

O título praticamente diz tudo. Qual é a maneira mais simples / elegante de converter, em Java, uma string do formato "THIS_IS_AN_EXAMPLE_STRING"para o formato " ThisIsAnExampleString"? Eu acho que deve haver pelo menos uma maneira de fazer isso usando String.replaceAll()e uma regex.

Meus pensamentos iniciais são: acrescente a sequência com um sublinhado ( _), converta a sequência inteira em minúscula e, em seguida, use replaceAll para converter todos os caracteres precedidos por um sublinhado com sua versão em maiúscula.

Matt Ball
fonte
12
Nota do editor, 2015-03: os "pensamentos iniciais" acima são super burros. Você aprende muito sobre a construção de software em seis anos.
Matt Bola
4
Naquele momento em que você pergunta 'que idiota escreveu isso' e olha no controle de origem para encontrar aquele jovem e estúpido que você fez. Estive lá, fiz isso.
pierus 04/12/2015
@ MattBall: Eu gosto da versão inicial dos pensamentos, ela não requer uma biblioteca e só precisa de uma concatenação de strings e duas substituições de expressões regulares.
Konrad Höffner

Respostas:

192

Outra opção é usar o Google Guava's com.google.common.base.CaseFormat

George Hawkins deixou um comentário com este exemplo de uso:

CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");
Arnout Engelen
fonte
3
Consulte o comentário de George Hawkins [usuário: 245602] para um exemplo. stackoverflow.com/questions/1143951/…
Michael Scheper
5
Sinto falta de respostas java puras enquanto desenvolvo para o Android.
eliocs 6/11/14
1
Esta resposta é a mais útil para mim. Eu poderia muito bem escrever meu próprio código, mas se alguém já o tiver, certamente não quero reinventar a roda.
James Dunn
Consulte stackoverflow.com/questions/10310321/… também
Hartmut P.
1
@ CléssioMendes você já pensou em fazer isso em github.com/google/guava/issues ?
Arnout Engelen
128

Dê uma olhada no WordUtils na biblioteca do Apache Commons lang :

Especificamente, o método capitalizeFully (String str, char [] delimitadores) deve fazer o trabalho:

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

Barra verde!

Dan Gravell
fonte
55
Não senhor! Devemos reescrever esses utilitários já existentes, já que estamos trabalhando, pois somos programadores adequados!
21410 skaffman
24
São 16:42 em uma tarde de sexta-feira. Eu vou deixar todo mundo reescrevê-lo, eu vou sair para uma cerveja \ o /;)
Dan Gravell
1
Mais exatamente, nem tenho acesso a esse pacote específico com a minha configuração atual e, como realmente (ainda) não preciso de nada além do método capitalizeFully, não perco nada escrevendo ele mesmo.
21710 Matt Ball
7
Eu respeito sua decisão, Matt, provavelmente é a coisa certa a fazer em sua posição. No entanto, considere o seguinte: * Alguém da sua equipe decide que precisa de uma rotina para trocar o caso das letras. Eles o implementam. Agora você tem ~ 20 linhas para manter. Você teria ~ 2 se usasse a biblioteca. E não se esqueça dos testes de unidade! * A resposta aceita tem uma desvantagem, pois o nome do método não descreve o que o código faz. Uma API bem reutilizada, como as coisas comuns, raramente tem essas desvantagens. O ponto é que a manutenção é o maior custo do software. Geralmente, a reutilização é uma boa ideia.
Dan Gravell 22/07/2009
2
Para "acessar este pacote específico", solte repo1.maven.org/maven2/commons-lang/commons-lang/2.5/… em seu caminho de classe. O artefato Maven é commons-lang: commons-lang: 2.5 e está prontamente disponível no 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();
}

Nota : Você precisa adicionar a validação de argumento.

Cruz
fonte
1
Boa resposta, mas seria um pouco melhor se o nome do método descrevesse o fato de que a string foi dividida ou que a lógica foi externalizada e o método chama alinhado como um canal, por exemplo, "THIS_IS_AN_EXAMPLE_STRING" .removeUnderscores (). ToCamelCase () This é mais reutilizável.
22611 Dan Gravell
1
Isso não é necessariamente melhor (embora sim, é mais reutilizável). Quando se trata de convenções de formatação de nomes, o camelcase pode / implica não usar sublinhados; no verso da moeda, existem convenções que especificam o uso de sublinhados. Então, na minha opinião, este é apenas um método para converter de um formato para outro.
23415 Matt Ball
58
A biblioteca de goiabas do Google possui um enum de utilidade mais geral para a conversão entre as convenções comuns. Para este caso, você faria String result = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");. Consulte javadoc com.google.common.base.CaseFormat .
21811 George Hawkins
1
Esta resposta terá problemas quando usada em locais como o turco ... Se o seu código for usado em vários locais, use toUpperCase (Locale) e toLowercase (Locale) .. não os que dependem do local padrão.
Vkraemer
2
@ DanGravell: depois de remover os sublinhados, não é mais possível distinguir as palavras.
Njzk2 09/10
18

Com o Apache Commons Lang3 lib é muito fácil.

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

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

Exemplo:

getName("SOME_CONSTANT");

Dá:

"SomeConstant"
librucha
fonte
2
No caso do nome da variável, isso não é válido porque o nome deve começar com letras minúsculas.
Seby 11/01
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);
}
Yishai
fonte
3
o teste s.length não é necessário
njzk2 09/10
9

Aqui está um trecho de código que pode ajudar:

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
Alex B
fonte
Esta solução é apropriada para o caso ALL_UPPER to Camel. Mas uma ligeira mudança no programa também pode lidar com MixED_case ou lower_case (caso de cobra). Sugeri uma edição, se permitido.
sud007 16/08/19
6

Exemplo de Java 1.8 usando Streams

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 agora é thisIsSomeText

Mike
fonte
Eu gosto dessa resposta, mas há uma falha se a sequência de entrada já estiver no caso de camelo, caso em que diminui a entrada inteira. por exemplo, abcDef se torna abcdef.
mrswadge
Um teste usando text.matches( "([a-z]+[a-zA-Z0-9]+)+" )antes da carcaça do camelo é provavelmente uma solução razoável para o problema da carcaça inferior.
mrswadge
2

Não tenho certeza, mas acho que posso usar menos memória e obter um desempenho confiável fazendo isso, char a char. Eu estava fazendo algo semelhante, mas em loops em threads de segundo plano, então estou tentando isso por enquanto. Eu tive alguma experiência com String.split sendo mais caro do que o esperado. E estou trabalhando no Android e espero que os soluços da GC sejam mais um problema do que o uso da 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();
  }

Uma dica de que String.split é caro é que sua entrada é um regex (não um caractere como String.indexOf) e retorna uma matriz (em vez de dizer um iterador porque o loop usa apenas uma coisa de cada vez). Além disso, casos como "AB_AB_AB_AB_AB_AB ..." quebram a eficiência de qualquer cópia em massa e, para seqüências longas, usa uma ordem de magnitude mais memória que a sequência de entrada.

Considerando que o loop através de caracteres não tem caso canônico. Então, para mim, a sobrecarga de um regex e matriz desnecessários geralmente parece menos preferível (desistindo da possível eficiência da cópia em massa). Interessado em ouvir opiniões / correções, obrigado.

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

Tempos: em mili segundos.

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
Srisa
fonte
Legal, isso está iterando com a entrada "THIS_IS_AN_EXAMPLE_STRING"?
leorleor
Iteração @leorleor = 1000000000 WithChars: start = 1387547394726 end = 1387547889896 diff = 495170 WithRegex: start = 1387547889897 end = 1387548944739 diff = 1054842
Srisa
1

Você pode usar org.modeshape.common.text.Inflector .

Especificamente:

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

Por padrão, esse método converte seqüências de caracteres em UpperCamelCase.

O artefato do Maven é: org.modeshape: modeshape-common: 2.3.0.Final

no repositório JBoss: https://repository.jboss.org/nexus/content/repositories/releases

Aqui está o arquivo JAR: https://repository.jboss.org/nexus/content/repositories/releases/org/modeshape/modeshape-common/2.3.0.Final/modeshape-common-2.3.0.Final.jar

Hendy Irawan
fonte
1

Você pode tentar isso também:

 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;
    }
Ashish
fonte
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;
}
Muzikant
fonte
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;
}

Este é o programa mais simples para converter para o CamelCase. espero que ajude você ..

XORG_99
fonte
0

Ele será convertido Enum Constantem Camel Case. Seria útil para quem procura essa funcionalidade.

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

Mais uma solução para isso pode ser a seguinte.

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

}

Invocação como

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

Tempo de execução: 14 ms

Arindam
fonte
0

Um snnipet simples:

 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;
}
fitorec
fonte
-2

Java 8 para várias cadeias:

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) + ", "));
DET66
fonte
1
Resposta duplicada
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());

    }
Vladimir
fonte
1
CaseFormatnão é uma API padrão. Resposta duplicada, se for goiaba.
precisa saber é o seguinte