Regex для преобразования CamelCase в camel_case в java

Я понимаю, почему желаемый результат не задан для преобразования с использованием regex строки типа FooBar в Foo_Bar, которая вместо этого дает Foo_Bar_. Я мог бы что-то сделать с String.substring substring(0, string.length() - 2) или просто заменить последний символ, но я думаю, что есть лучшее решение для такого сценария.

Вот код:

String regex = "([A-Z][a-z]+)";
String replacement = "$1_";

"CamelCaseToSomethingElse".replaceAll(regex, replacement); 

/*
outputs: Camel_Case_To_Something_Else_
desired output: Camel_Case_To_Something_Else
*/

Вопрос: Ищете более простой способ получить желаемый результат?

Ответ 1

Смотрите этот вопрос и CaseFormat из гуавы

в вашем случае что-то вроде:

CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");

Ответ 2

свяжите нижний регистр и верхний регистр как две группы, это будет нормально

public  class Main
{
    public static void main(String args[])
    {
        String regex = "([a-z])([A-Z]+)";
        String replacement = "$1_$2";
        System.out.println("CamelCaseToSomethingElse"
                           .replaceAll(regex, replacement)
                           .toLowerCase());
    }
}

Ответ 3

Вы можете использовать ниже фрагмент кода:

String replaceAll = key.replaceAll("(.)(\\p{Upper})", "$1_$2").toLowerCase();

Ответ 4

Почему бы просто не совместить предшествующий символ как не начало строки $?

String text = "CamelCaseToSomethingElse";
System.out.println(text.replaceAll("([^_A-Z])([A-Z])", "$1_$2"));

Обратите внимание, что эта версия безопасна для выполнения чего-то, что уже с верблюдом.

Ответ 5

Добавить утверждение с нулевой шириной.

http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html

Прочитайте документацию для (?=X) и т.д.

Лично я бы на самом деле разделил строку, а затем рекомбинировал ее. Это может быть даже быстрее, когда это делается правильно, и это делает код намного понятнее, чем магия регулярного выражения. Не поймите меня неправильно: я люблю регулярные выражения. Но это не очень аккуратное регулярное выражение, и это преобразование не является классической задачей регулярного выражения. В конце концов, кажется, вы также хотите сделать строчные буквы?

Уродливым, но быстрым взломом было бы заменить (.)([A-Z]+) на $1_$2, а затем записать нижнюю строчку всей строки (если только вы не можете использовать расширенные регулярные выражения в стиле perl, где вы можете напрямую спрятать замену!). Тем не менее, я рассматриваю расщепление при переходе от нижнего к верхнему, а затем преобразование, а затем соединение как правильный и наиболее читаемый способ сделать это.

Ответ 6

Я не могу предоставить RegEx, это было бы безумно сложно в любом случае.

Попробуйте эту функцию с автоматическим распознаванием сокращений.

К сожалению, библиотека Guava не может автоматически определять прописные буквы, поэтому "bigCAT" будет преобразован в "BIG_C_A_T".

/**
 * Convert to UPPER_UNDERSCORE format detecting upper case acronyms
 */
private String upperUnderscoreWithAcronyms(String name) {
    StringBuffer result = new StringBuffer();
    boolean begin = true;
    boolean lastUppercase = false;
    for( int i=0; i < name.length(); i++ ) {
        char ch = name.charAt(i);
        if( Character.isUpperCase(ch) ) {
            // is start?
            if( begin ) {
                result.append(ch);
            } else {
                if( lastUppercase ) {
                    // test if end of acronym
                    if( i+1<name.length() ) {
                        char next = name.charAt(i+1);
                        if( Character.isUpperCase(next) ) {
                            // acronym continues
                            result.append(ch);
                        } else {
                            // end of acronym
                            result.append('_').append(ch);
                        }
                    } else {
                        // acronym continues
                        result.append(ch);
                    }
                } else {
                    // last was lowercase, insert _
                    result.append('_').append(ch);
                }
            }
            lastUppercase=true;
        } else {
            result.append(Character.toUpperCase(ch));
            lastUppercase=false;
        }
        begin=false;
    }
    return result.toString();
}

Ответ 7

public class ReplaceFromCameltoSnake {
    public static void main(String args[]){
        String s1=" totalAmountWithoutDiscount";  
        String replaceString=s1.replaceAll("([A-Z]+)","\\_$1").toLowerCase(); 
        System.out.println(replaceString);  
    }
}

Ответ 8

([A-Z][a-z\d]+)(?=([A-Z][a-z\d]+))

Должен искать заглавную букву, за которой следуют строчные буквы. Позитивный взгляд будет искать другое слово, начинающееся с заглавной буквы, за которой следуют строчные буквы, но НЕ будет включать его в матч.

Посмотрите здесь: http://regexr.com?30ooo

Ответ 9

Мне пришлось реализовать это, чтобы преобразовать некоторые ключи в верблюжьем формате в нижний регистр с подчеркиванием. Регулярное выражение, которое я придумал:

(?<!^|_|[AZ])([AZ])

В английском это означает заглавную букву, которой не предшествует начало строки, подчеркивание или другая заглавная буква.

В приведенных ниже примерах жирным шрифтом обозначены те символы, которые должны соответствовать, используя вышеупомянутое регулярное выражение:

  • Верблюд С аза Т о S omething Е ЛСЭ
  • верблюд С аза Т о S omething Е ЛСЭ
  • camel_case_to_something_else
  • camel_case_to_something_else
  • camel_case_to_something_else

Обратите внимание, что выражение не влияет на строку, которая уже в нижнем регистре + символ подчеркивания.

Шаблон замены будет:

_l$1

Что означает строчную букву первой группы захвата, причем первая группа захвата является заглавной буквой. Впоследствии вы также можете записать всю строку в нижнем регистре, чтобы нормализовать последние два образца из списка выше.

Ответ 10

Не уверен, что можно получить что-то действительно с чистым регулярным выражением. Особенно в поддержку аббревиатур.

Я сделал небольшую функцию, вдохновленную ответом @radzimir, которая поддерживает аббревиатуры и не содержит буквенных символов:

С https://gist.github.com/ebuildy/cf46a09b1ac43eea17c7621b7617ebcd:

private static String snakeCaseFormat(String name) {
    final StringBuilder result = new StringBuilder();

    boolean lastUppercase = false;

    for (int i = 0; i < name.length(); i++) {
        char ch = name.charAt(i);
        char lastEntry = i == 0 ? 'X' : result.charAt(result.length() - 1);
        if (ch == ' ' || ch == '_' || ch == '-' || ch == '.') {
            lastUppercase = false;

            if (lastEntry == '_') {
                continue;
            } else {
                ch = '_';
            }
        } else if (Character.isUpperCase(ch)) {
            ch = Character.toLowerCase(ch);
            // is start?
            if (i > 0) {
                if (lastUppercase) {
                    // test if end of acronym
                    if (i + 1 < name.length()) {
                        char next = name.charAt(i + 1);
                        if (!Character.isUpperCase(next) && Character.isAlphabetic(next)) {
                            // end of acronym
                            if (lastEntry != '_') {
                                result.append('_');
                            }
                        }
                    }
                } else {
                    // last was lowercase, insert _
                    if (lastEntry != '_') {
                        result.append('_');
                    }
                }
            }
            lastUppercase = true;
        } else {
            lastUppercase = false;
        }

        result.append(ch);
    }
    return result.toString();
}