Який найпростіший спосіб перетворити рядок Java з усіх заголовків (слова, розділені підкресленнями), у CamelCase (немає розділювачів слів)?


152

Назва майже все це говорить. Який найпростіший / найелегантніший спосіб перетворити рядок у формат "THIS_IS_AN_EXAMPLE_STRING"у формат " ThisIsAnExampleString" у Java ? Я вважаю, що повинен бути принаймні один спосіб зробити це за допомогою String.replaceAll()і регулярного вираження.

Мої початкові думки такі: додайте рядок з підкресленням ( _), перетворіть всю нитку в малі регістри, а потім скористайтесь командою substituAll для перетворення кожного символу, який передує підкресленню, з його великої версії.


12
Примітка редактора, 2015-03 р.: "Початкові думки" вище - дуже німі. Ви багато дізнаєтесь про створення програмного забезпечення за шість років.
Метт Бал

4
Той момент, коли ви запитуєте "який ідіот написав це", і дивитесь в контролі джерел, щоб знайти того молодого, дурного, що ви зробили. Був там зробив те.
пір

@MattBall: Мені подобається початкова версія думок, вона не потребує бібліотеки і просто потребує конкатенації рядків та двох замінок регулярних виразів.
Конрад Геффнер

Відповіді:


192

Іншим варіантом є використання Google Guava com.google.common.base.CaseFormat

Джордж Хокінс залишив коментар щодо цього прикладу використання:

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

3
Для прикладу зверніться до коментаря Джорджа Хокінса [користувача: 245602]. stackoverflow.com/questions/1143951/…
Майкл Шепер

5
Я пропускаю чисті відповіді на Java, коли розробляю для Android.
еліоки

1
Ця відповідь для мене найбільш корисна. Я міг би дуже добре написати власний код, але якщо хтось уже є, я, звичайно, не хочу винаходити колесо.
Джеймс Данн

Зверніться до stackoverflow.com/questions/10310321/… також
Hartmut P.

1
@ CléssioMendes Ви думали про те, як це зробити на веб- сайті github.com/google/guava/isissue ?
Арнут Енгелен

128

Погляньте на WordUtils у бібліотеці мови Apache Commons :

Зокрема, метод capitalizeFully (String str, char [] роздільники) повинен виконати цю роботу:

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

Зелена смужка!


55
Ні, сер! Ми повинні самі переписати ці існуючі, вже працюючі утиліти, бо ми належні програмісти!
скафман

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.
Хенді Іраван

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 .
Джордж Хокінс

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
тест на міцність на довжину не потрібен
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 або нижньою коробкою (зміїний чохол). Я запропонував редагувати, якщо це дозволено.
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 зараз цеIsSomeText


Мені подобається ця відповідь, але у неї є недолік, якщо рядок введення вже є у справі верблюда, і в цьому випадку вона знижує регістри всього введення. наприклад, abcDef стає abcdef.
mrswadge

Тест із застосуванням text.matches( "([a-z]+[a-zA-Z0-9]+)+" )до кожуха верблюдів, ймовірно, є розумним вирішенням питання щодо нижнього корпусу.
mrswadge

2

Не впевнений, але я думаю, що я можу використовувати менше пам’яті та отримувати надійні показники, роблячи це чар-чар-чар. Я робив щось подібне, але в петлях у фонових нитках, тому зараз це намагаюся. Я мав певний досвід, коли String.split був дорожчим, ніж очікувалося. І я працюю на Android і очікую, що гикавка GC буде більшою проблемою, ніж використання процесора.

  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 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.

Артефакт Мейвена - це: org.modeshape: modehape-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на верблюдний кейс. Було б корисно для всіх, хто шукає такої функціональності.

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)

Час виконання: 14 мс


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) + ", "));


-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. Дублікат відповіді, якщо це Гуава.
Марк Єронімус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.