Как проще всего преобразовать строку Java из всех прописных букв (слов, разделенных подчеркиванием) в CamelCase (без разделителей слов)?


152

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

Мои первоначальные мысли таковы: добавьте строку с подчеркиванием ( _), преобразуйте всю строку в нижний регистр, а затем используйте replaceAll, чтобы преобразовать каждый символ, которому предшествует подчеркивание, с его заглавной версией.


12
Примечание редактора, 2015-03: «начальные мысли» выше очень глупы. Вы много узнаете о создании программного обеспечения за шесть лет.
Мэтт Болл

4
В тот момент, когда вы спрашиваете «что идиот написал это» и смотрите в систему контроля версий, чтобы найти того молодого, глупого, которого вы сделали. Был там, сделал это.
Pierus

@MattBall: мне нравится первоначальная версия Мысли, она не требует библиотеки и просто требует объединения строк и двух замен регулярных выражений.
Конрад

Ответы:


192

Другой вариант использует Google Guava's 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.
eliocs

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

Обратитесь к stackoverflow.com/questions/10310321/… также
Хартмут П.

1
@ CléssioMendes вы рассматривали вопрос об этом на github.com/google/guava/issues ?
Арно Энгелен

128

Взгляните на WordUtils в библиотеке языка Apache Commons :

В частности, метод capitalizeFully (String str, char [] delimiters) должен выполнить эту работу:

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

Зеленая полоса!


55
Нет, сэр! Мы должны сами переписать эти существующие, уже работающие утилиты, потому что мы правильные программисты!
Скаффман

24
Сегодня в пятницу 16:42. Я позволю всем остальным переписать его, я иду на пиво \ o /;)
Дэн Гравелл

1
Более того, у меня даже нет доступа к этому конкретному пакету с моими текущими настройками, и, поскольку мне действительно (пока) не нужно ничего, кроме метода capitalizeFully, я ничего не теряю, написав его сам.
Мэтт Болл

7
Я уважаю твое решение, Мэтт, это, наверное, правильно делать в твоем положении. Однако учтите следующее: * Кто-то еще в вашей команде решает, что ему нужна процедура, чтобы поменять регистр букв. Они реализуют это. Теперь у вас есть ~ 20 строк для обслуживания. Вы бы получили ~ 2, если бы использовали библиотеку. И не забудьте модульные тесты! * Принятый ответ имеет недостаток в том, что имя метода не описывает, что делает код. У хорошо повторно используемого API, такого как обычные вещи, редко бывают такие недостатки. Дело в том, что обслуживание - это самая большая стоимость программного обеспечения. Как правило, повторное использование является хорошей идеей.
Дэн Гравелл

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 () Это является более многоразовым.
Дэн Гравелл

1
Это не обязательно лучше (хотя да, это более многоразово). Когда дело доходит до соглашений о форматировании имен, camelcase может / не подразумевает использование подчеркивания; на обратной стороне монеты есть условные обозначения, которые указывают использование подчеркивания. Так что, на мой взгляд, это просто метод для преобразования из одного формата в другой.
Мэтт Болл

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) .. не те, которые зависят от локали по умолчанию.
вкраемер

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
В случае имени переменной это недопустимо, потому что имя должно начинаться со строчной буквы.
Себи

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 или 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 теперь thisSsSomeText


Мне нравится этот ответ, но у него есть недостаток, если входная строка уже находится в верблюжьем регистре, и в этом случае она вводит нижний регистр всего ввода. например, abcDef становится abcdef.
mrswadge

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

2

Не уверен, но я думаю, что смогу использовать меньше памяти и получить надежную производительность, выполняя ее по принципу char-by-char. Я делал что-то подобное, но в циклах в фоновых потоках, поэтому я пытаюсь это сейчас. У меня был некоторый опыт работы с 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

@leorleor Iteration = 1000000000 WithChars: start = 1387547394726 end = 1387547889896 diff = 495170 WithRegex: start = 1387547889897 end = 1387548944739 diff = 1054842
Сриса,

1

Вы можете использовать org.modeshape.common.text.Inflector .

В частности:

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

По умолчанию этот метод преобразует строки в UpperCamelCase.

Артефакт Maven: org.modeshape: commonhape-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) + ", "));

1
Двойной ответ
Марк Иеронимус

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