Was ist der einfachste Weg, um eine Java-Zeichenfolge von allen Großbuchstaben (durch Unterstriche getrennte Wörter) in CamelCase (keine Worttrennzeichen) zu konvertieren?

151

Der Titel sagt so ziemlich alles. Was ist die einfachste / eleganteste Art, wie ich in Java eine Zeichenfolge vom Format "THIS_IS_AN_EXAMPLE_STRING"in das Format " ThisIsAnExampleString" konvertieren kann ? Ich denke, es muss mindestens einen Weg geben, dies zu tunString.replaceAll() einem regulären Ausdruck .

Meine ersten Gedanken sind: Stellen Sie der Zeichenfolge einen Unterstrich ( _) voran, konvertieren Sie die gesamte Zeichenfolge in Kleinbuchstaben und konvertieren Sie dann mit replaceAll jedes Zeichen, dem ein Unterstrich mit seiner Großbuchstabenversion vorangestellt ist.

Matt Ball
quelle
12
Anmerkung des Herausgebers, 2015-03: Die "ersten Gedanken" oben sind super dumm. In sechs Jahren lernen Sie viel über das Erstellen von Software.
Matt Ball
4
In dem Moment, in dem Sie fragen, welcher Idiot das geschrieben hat, und in der Quellcodeverwaltung nach dem jungen, dummen Mann suchen, den Sie getan haben. Kenne ich schon.
Pierus
@MattBall: Ich mag die anfängliche Gedankenversion, sie erfordert keine Bibliothek und benötigt nur eine String-Verkettung und zwei Regex-Ersetzungen.
Konrad Höffner

Antworten:

192

Eine weitere Option ist die Verwendung von Google Guava com.google.common.base.CaseFormat

George Hawkins hat einen Kommentar zu diesem Anwendungsbeispiel hinterlassen:

CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");
Arnout Engelen
quelle
3
Ein Beispiel finden Sie im Kommentar von George Hawkins [Benutzer: 245602]. stackoverflow.com/questions/1143951/…
Michael Scheper
5
Ich vermisse reine Java-Antworten, während ich für Android entwickle.
Eliocs
1
Diese Antwort ist für mich am nützlichsten. Ich könnte sehr gut meinen eigenen Code schreiben, aber wenn jemand anderes ihn bereits hat, möchte ich das Rad auf keinen Fall neu erfinden.
James Dunn
1
@ CléssioMendes Haben Sie darüber nachgedacht, dies unter github.com/google/guava/issues zu erwähnen ?
Arnout Engelen
128

Schauen Sie sich WordUtils in der Apache Commons lang- Bibliothek an:

Insbesondere sollte die Methode capitalizeFully (String str, char [] delimiters) die folgende Aufgabe ausführen:

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

Grüner Balken!

Dan Gravell
quelle
55
Nein Sir! Wir sollten diese vorhandenen, bereits funktionierenden Dienstprogramme selbst neu schreiben, denn wir sind richtige Programmierer!
Skaffman
24
Es ist 16:42 Uhr an einem Freitagnachmittag. Ich lasse es alle anderen umschreiben, ich gehe auf ein Bier aus \ o /;)
Dan Gravell
1
Genauer gesagt, ich habe mit meinem aktuellen Setup nicht einmal Zugriff auf dieses bestimmte Paket, und da ich (noch) nichts über die Methode "capitalizeFully" hinaus benötige, verliere ich nichts, wenn ich es selbst schreibe.
Matt Ball
7
Ich respektiere deine Entscheidung Matt, es ist wahrscheinlich das Richtige in deiner Position. Beachten Sie jedoch Folgendes: * Jemand anderes in Ihrem Team entscheidet, dass er eine Routine benötigt, um den Fall von Briefen auszutauschen. Sie setzen es um. Sie müssen jetzt ~ 20 Zeilen pflegen. Sie hätten ~ 2, wenn Sie die Bibliothek verwenden würden. Und vergessen Sie nicht die Unit-Tests! * Die akzeptierte Antwort hat den Nachteil, dass der Methodenname nicht beschreibt, was der Code tut. Eine gut wiederverwendete API wie das Commons-Zeug hat selten diese Nachteile. Der Punkt ist, dass Wartung die größten Kosten für Software ist. Im Allgemeinen ist die Wiederverwendung eine gute Idee.
Dan Gravell
2
Um "auf dieses bestimmte Paket zuzugreifen", legen Sie repo1.maven.org/maven2/commons-lang/commons-lang/2.5/… in Ihrem Klassenpfad ab. Das Maven-Artefakt ist commons-lang: commons-lang: 2.5 und ist in Maven Central erhältlich.
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();
}

Hinweis : Sie müssen die Argumentvalidierung hinzufügen.

Kreuz
quelle
1
Gute Antwort, aber es wäre ein bisschen besser, wenn entweder der Methodenname die Tatsache beschreibt, dass die Zeichenfolge geteilt wurde oder dass die Logik ausgelagert und die Methodenaufrufe als Pipe ausgerichtet wurden, z. B. "THIS_IS_AN_EXAMPLE_STRING" .removeUnderscores (). ToCamelCase () This ist wiederverwendbarer.
Dan Gravell
1
Das ist nicht unbedingt besser (obwohl ja, es ist wiederverwendbarer). Wenn es um Namensformatierungskonventionen geht, kann / bedeutet camelcase, dass keine Unterstriche verwendet werden. Auf der Rückseite der Münze befinden sich Konventionen, die die Verwendung von Unterstrichen festlegen. In meinen Augen ist dies nur eine Methode, um von einem Format in ein anderes zu konvertieren.
Matt Ball
58
Die Google Guava-Bibliothek verfügt über eine allgemeinere Dienstprogramm-Enumeration für die Konvertierung zwischen den allgemeinen Konventionen. Für diesen Fall würden Sie tun String result = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");. Siehe com.google.common.base.CaseFormat javadoc .
George Hawkins
1
Diese Antwort stößt auf Probleme, wenn sie in Gebietsschemas wie Türkisch verwendet wird. Wenn Ihr Code in mehreren Gebietsschemas verwendet werden soll, verwenden Sie toUpperCase (Gebietsschema) und toLowercase (Gebietsschema). Dies sind nicht diejenigen, die vom Standardgebietsschema abhängen.
Vkraemer
2
@DanGravell: Sobald Sie die Unterstriche entfernt haben, ist es nicht mehr möglich, die Wörter zu unterscheiden.
NJZK2
18

Mit Apache Commons Lang3 lib ist das sehr einfach.

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

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

Beispiel:

getName("SOME_CONSTANT");

Gibt:

"SomeConstant"
Librucha
quelle
2
Bei Variablennamen ist dies nicht gültig, da der Name mit Kleinbuchstaben beginnen muss.
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);
}
Yishai
quelle
3
der s.length test ist nicht notwendig
njzk2
9

Hier ist ein Code-Snippet, das helfen könnte:

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.
quelle
Diese Lösung ist für den Fall ALL_UPPER to Camel geeignet. Eine geringfügige Änderung im Programm kann jedoch auch MixED_case oder Kleinbuchstaben (Snake Case) verarbeiten. Ich habe eine Bearbeitung vorgeschlagen, wenn dies zulässig ist.
Sud007
6

Java 1.8-Beispiel mit 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 ist jetzt thisIsSomeText

Mike
quelle
Ich mag diese Antwort, aber sie hat einen Fehler, wenn sich die Eingabezeichenfolge bereits im Kamelfall befindet. In diesem Fall wird die gesamte Eingabe in Kleinbuchstaben geschrieben. zB wird abcDef zu abcdef.
Frau Wadge
Ein Test text.matches( "([a-z]+[a-zA-Z0-9]+)+" )vor der Kamelhülle ist wahrscheinlich eine vernünftige Problemumgehung für das Problem der unteren Hülle.
Frau Wadge
2

Ich bin mir nicht sicher, aber ich denke, ich kann weniger Speicher verwenden und eine zuverlässige Leistung erzielen, indem ich es char-by-char mache. Ich habe etwas Ähnliches gemacht, aber in Schleifen in Hintergrund-Threads, also versuche ich das jetzt. Ich habe einige Erfahrungen damit gemacht, dass String.split teurer ist als erwartet. Und ich arbeite an Android und erwarte, dass GC-Schluckauf eher ein Problem als die Verwendung von CPUs ist.

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

Ein Hinweis darauf, dass String.split teuer ist, ist, dass seine Eingabe ein regulärer Ausdruck ist (kein Zeichen wie String.indexOf) und ein Array zurückgibt (anstelle eines Iterators, da die Schleife jeweils nur eine Sache verwendet). Plus-Fälle wie "AB_AB_AB_AB_AB_AB ..." beeinträchtigen die Effizienz von Massenkopien und verwenden für lange Zeichenfolgen eine Größenordnung mehr Speicher als die Eingabezeichenfolge.

Während das Durchlaufen von Zeichen keinen kanonischen Fall hat. Daher scheint mir der Overhead eines nicht benötigten regulären Ausdrucks und Arrays im Allgemeinen weniger vorzuziehen zu sein (und dann die mögliche Effizienz von Massenkopien aufzugeben). Interessiert, Meinungen / Korrekturen zu hören, danke.

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

Zeiten: in Millisekunden.

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
quelle
Cool, iteriert das mit der Eingabe "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

Sie können org.modeshape.common.text.Inflector verwenden .

Speziell:

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

Standardmäßig konvertiert diese Methode Zeichenfolgen in UpperCamelCase.

Maven-Artefakt ist: org.modeshape: modeshape-common: 2.3.0.Final

im JBoss-Repository: https://repository.jboss.org/nexus/content/repositories/releases

Hier ist die JAR-Datei: 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
quelle
1

Sie können dies auch versuchen:

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

Dies ist das einfachste Programm, das in CamelCase konvertiert werden kann. hoffe es wird dir helfen ..

XORG_99
quelle
0

Es wird Enum Constantin Camel Case umgewandelt. Es wäre hilfreich für alle, die nach einer solchen Funktionalität suchen.

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_
quelle
0

Eine weitere Lösung hierfür kann wie folgt sein.

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

}

Aufruf als

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

Ausführungszeit: 14 ms

Arindam
quelle
0

Ein einfaches 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;
}
fitorec
quelle
-2

Java 8 für mehrere Zeichenfolgen:

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
quelle
1
Doppelte Antwort
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
quelle
1
CaseFormatist keine Standard-API. Doppelte Antwort, wenn es Guave ist.
Mark Jeronimus