Qual è il modo più semplice per convertire una stringa Java da tutte le maiuscole (parole separate da caratteri di sottolineatura) in CamelCase (senza separatori di parole)?


152

Il titolo praticamente dice tutto. Qual è il modo più semplice / elegante in cui posso convertire, in Java, una stringa dal formato "THIS_IS_AN_EXAMPLE_STRING"al formato " ThisIsAnExampleString"? Immagino che ci debba essere almeno un modo per farlo usando String.replaceAll()e una regex.

I miei pensieri iniziali sono: anteporre la stringa con un carattere di sottolineatura ( _), convertire l'intera stringa in lettere minuscole, quindi utilizzare ReplaceAll per convertire ogni carattere preceduto da un carattere di sottolineatura con la sua versione maiuscola.


12
Nota del redattore, 2015-03: i "pensieri iniziali" sopra sono super stupidi. In sei anni impari molto sulla costruzione di software.
Matt Ball,

4
Quel momento in cui chiedi "cosa ha scritto questo idiota" e guardi nel controllo del codice sorgente per trovare quel giovane, stupido che hai fatto. Ci sono stato, l'ho fatto.
pierus,

@MattBall: mi piace la versione iniziale dei pensieri, non richiede una libreria e necessita solo di una concatenazione di stringhe e di due sostituzioni regex.
Konrad Höffner,

Risposte:


192

Un'altra opzione è utilizzare Google Guava com.google.common.base.CaseFormat

George Hawkins ha lasciato un commento con questo esempio di utilizzo:

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

3
Fare riferimento al commento di George Hawkins [utente: 245602] per un esempio. stackoverflow.com/questions/1143951/…
Michael Scheper,

5
Mi mancano le risposte java pure mentre sto sviluppando per Android.
eliocs,

1
Questa risposta è la più utile per me. Potrei benissimo scrivere il mio codice, ma se qualcun altro lo ha già fatto, non voglio certo reinventare la ruota.
James Dunn,


1
@ CléssioMendes hai preso in considerazione l'idea di presentarlo su github.com/google/guava/issues ?
Arnout Engelen,

128

Dai un'occhiata a WordUtils nella libreria di lingue di Apache Commons :

In particolare, il metodo capitalizeFully (String str, char [] delimiters) dovrebbe fare il lavoro:

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

Barra verde!


55
No signore! Dovremmo riscrivere noi stessi questi programmi di utilità esistenti e già funzionanti, poiché siamo dei veri programmatori!
Skaffman,

24
Sono le 16:42 di venerdì pomeriggio. Lascerò riscrivere tutti gli altri, esco per una birra \ / /;)
Dan Gravell,

1
Più precisamente, non ho nemmeno accesso a quel particolare pacchetto con la mia configurazione attuale e dal momento che non ho (ancora) davvero bisogno di qualcosa oltre il metodo capitalizeFully, non perdo nulla scrivendolo da solo.
Matt Ball,

7
Rispetto la tua decisione Matt, è probabilmente la cosa giusta da fare nella tua posizione. Tuttavia, considera quanto segue: * Qualcun altro nella tua squadra decide di aver bisogno di una routine per scambiare il caso delle lettere. Lo implementano. Ora hai ~ 20 linee da mantenere. Avresti ~ 2 se usassi la libreria. E non dimenticare i test unitari! * La risposta accettata ha un aspetto negativo in quanto il nome del metodo non descrive ciò che fa il codice. Un'API ben riutilizzata come roba comune ha raramente questi aspetti negativi. Il punto è che la manutenzione è il costo maggiore del software. In generale, il riutilizzo è una buona idea.
Dan Gravell,

2
Per "accedere a questo particolare pacchetto", rilascia repo1.maven.org/maven2/commons-lang/commons-lang/2.5/… nel tuo percorso di classe. Il manufatto Maven è commons-lang: commons-lang: 2.5 ed è prontamente disponibile da Maven Central.
Hendy Irawan il

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 : è necessario aggiungere la convalida dell'argomento.


1
Bella risposta, ma sarebbe un po 'meglio se il nome del metodo descrivesse il fatto che la stringa fosse divisa o che la logica fosse esternalizzata e le chiamate del metodo allineate come pipe, ad es. "THIS_IS_AN_EXAMPLE_STRING" .removeUnderscores (). ToCamelCase () This è più riutilizzabile.
Dan Gravell,

1
Questo non è necessariamente migliore (anche se sì, è più riutilizzabile). Quando si tratta di convenzioni sulla formattazione dei nomi, camelcase può / non implica l'uso di caratteri di sottolineatura; sul rovescio della medaglia, ci sono convenzioni che specificano usando i trattini bassi. Quindi, nella mia mente, questo è solo un metodo per convertire da un formato all'altro.
Matt Ball

58
La libreria guava di Google ha un enum di utilità più generale per la conversione tra le convenzioni comuni. Per questo caso lo faresti String result = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");. Vedi com.google.common.base.CaseFormat javadoc .
George Hawkins,

1
Questa risposta si imbatterà in problemi se utilizzata in locali come il turco ... Se il tuo codice verrà utilizzato in più locali, usa toUpperCase (Locale) e toLowercase (Locale) .. non quelli che dipendono dalle impostazioni internazionali predefinite.
Vkraemer,

2
@DanGravell: una volta rimossi i caratteri di sottolineatura, non è più possibile distinguere le parole.
njzk2,

18

Con Apache Commons Lang3 lib è molto semplice.

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

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

Esempio:

getName("SOME_CONSTANT");

dà:

"SomeConstant"

2
In caso di nome variabile, questo non è valido perché il nome deve iniziare con lettere minuscole.
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
il test di lunghezza non è necessario
njzk2

9

Ecco uno snippet di codice che potrebbe aiutare:

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

Questa soluzione è appropriata per il caso da ALL_UPPER a Camel. Ma un leggero cambiamento nel programma può anche gestire MixED_case o lower_case (caso serpente). Ho suggerito una modifica se consentito.
sud007,

6

Esempio di 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 ora è thisIsSomeText


Mi piace questa risposta, ma ha un difetto se la stringa di input è già in caso di cammello, nel qual caso minuscola l'intero input. ad es. abcDef diventa abcdef.
mrswadge,

Un test che utilizza text.matches( "([a-z]+[a-zA-Z0-9]+)+" )prima dell'involucro del cammello è probabilmente una soluzione ragionevole per il problema dell'involucro inferiore.
mrswadge,

2

Non ne sono sicuro, ma penso di poter utilizzare meno memoria e ottenere prestazioni affidabili eseguendo le operazioni char-by-char. Stavo facendo qualcosa di simile, ma in loop nei thread in background, quindi per ora sto provando questo. Ho avuto qualche esperienza con String.split che è più costoso del previsto. E sto lavorando su Android e mi aspetto che il singhiozzo GC costituisca un problema maggiore rispetto all'utilizzo della 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();
  }

Un suggerimento che String.split è costoso è che il suo input è una regex (non un carattere come String.indexOf) e restituisce un array (invece di dire un iteratore perché il ciclo usa solo una cosa alla volta). Inoltre, casi come "AB_AB_AB_AB_AB_AB ..." interrompono l'efficienza di qualsiasi copia di massa e per stringhe lunghe usano un ordine di grandezza più memoria della stringa di input.

Considerando che scorrere i caratteri non ha un caso canonico. Quindi per me l'overhead di una regex e di una matrice non necessari in genere sembra meno preferibile (quindi rinunciare alla possibile efficienza di copia bulk). Interessato a ricevere opinioni / correzioni, grazie.


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

Tempi: in milli secondi.

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

Bene, è iterando con l'ingresso "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

Puoi usare org.modeshape.common.text.Inflector .

In particolare:

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

Per impostazione predefinita, questo metodo converte le stringhe in UpperCamelCase.

Il manufatto di Maven è: org.modeshape: modeshape-common: 2.3.0.Final

sul repository JBoss: https://repository.jboss.org/nexus/content/repositories/releases

Ecco il file 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

Puoi provare anche questo:

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

Questo è il programma più semplice per convertire in CamelCase. spero che ti possa aiutare ..


0

Si convertirà Enum Constantin Camel Case. Sarebbe utile per chiunque sia alla ricerca di tale funzionalità.

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

Un'altra soluzione a questo potrebbe essere la seguente.

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

}

Invocazione come

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

Tempo di esecuzione: 14 ms


0

Un semplice snnipet:

 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 per più stringhe:

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
Risposta duplicata
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
CaseFormatnon è un'API standard. Duplica risposta se è Guava.
Mark Jeronimus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.