Java에서 CamelCase를 camel_case로 변환하는 정규식


86

원하는 출력이 같은 문자열 정규식 사용하여 변환 제공되지 않는 이유 이해 FooBarFoo_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
*/

질문 : 원하는 출력을 얻을 수있는 깔끔한 방법을 찾고 계십니까?


답변:


171

질문CaseFormat구아바에서보기

귀하의 경우에는 다음과 같습니다.

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

@eliocs 질문에 android 및 "neater way"태그가 지정되지 않았습니다. 어쨌든 downvote 주셔서 감사합니다;)

2
CaseFormat 링크가 오프라인입니다. 교체가 시작 되었습니다
Anticom

66

소문자와 대문자를 두 그룹으로 묶으면 괜찮을 것입니다.

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

2
참고 : 입력 문자열에 단일 문자 단어가 허용되는 경우 (예 : "thisIsATest"), 위 코드는 "this_is_atest"를 인쇄합니다. 수락 된 답변에서 Guava는 "this_is_a_test"가됩니다.
DtotheK

이것은 대문자로 시작하는 이름 (예 :)에서는 작동하지 않습니다 IBMIsMyCompany.
User3301

37

아래 코드 스 니펫을 사용할 수 있습니다.

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

내 문자열에 숫자가 포함되어 있으면 mode3은 mode3으로 끝나는 반면 mode_3을 원합니다.
Mike Stoddart

카멜 케이스 MyUUID를 제대로 밑줄 로 변환하지 못합니다 my_uu_id.
User3301

6

RegEx를 제공 할 수 없습니다. 어쨌든 엄청나게 복잡 할 것입니다.

약어를 자동으로 인식하여이 기능을 사용해보십시오.

불행히도 Guava lib는 대문자 약어를 자동으로 감지하지 않으므로 "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();
}

5

단순히 행의 시작이 아닌 것으로 이전 문자와 일치하지 않는 이유는 무엇 $입니까?

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

이 버전은 이미 낙타 케이스에 넣어도 안전합니다.


^그리고 $앵커 로 사용하려고 합니까? 문자 클래스에 넣으면 의미가 바뀌기 때문입니다. [^$_A-Z]이외의 문자와 일치 $, _또는 대문자, 난 그게 당신이 무엇을 의미하는지 생각하지 않습니다.
Alan Moore

앵커로 의도하지 않고 대문자와 일치하지 않으려 고하고 있는데 $클래스 이름에 사용하는 기술이므로 실수로 추가되었습니다.
Brett Ryan

3

너비가 0 인 미리보기 어설 션을 추가합니다.

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

(?=X)기타 문서를 읽으십시오 .

개인적으로 나는 실제로 문자열을 분할 한 다음 다시 결합했습니다. 올바르게 수행하면 더 빠를 수 있으며 정규식 마술보다 코드를 훨씬 쉽게 이해할 수 있습니다. 오해하지 마세요. 저는 정규 표현식을 좋아합니다. 그러나 이것은 정말 깔끔한 정규 표현식이 아니며이 변환 은 고전적인 정규 표현식 작업도 아닙니다. 결국 소문자도하고 싶습니까?

못생긴하지만 빠른 해킹 교체하는 것 (.)([A-Z]+)으로 $1_$2하고 이후 전체 문자열을 소문자 (당신이 직접 교체를 소문자 수 펄 스타일 extrended regexps '에를 할 수 없다면!). 그래도 저는 아래에서 위로 전환 한 다음 변형 한 다음 결합하는 것이 적절하고 가장 읽기 쉬운 방법으로 분할하는 것을 고려합니다.


예, 결국 저도 소문자로하고 싶습니다.
ajmartin

그래서 나는 그것을 일치하는 청크로 분할 [A-Z][a-z]*하고 첫 글자를 소문자로하고 다시 결합합니다. 또는 메인 답장에 방금 추가 한 교체 + 소문자 트릭입니다.
Anony - 무스 - 종료 될

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

$ 1는 그룹을 만드는 데 사용됩니다
abinash sahu

2

순수한 정규식으로 무언가를 실제로 견고하게 할 수 있는지 확실하지 않습니다. 특히 약어를 지원합니다.

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

1
이것은 양질의 답변이며 대부분의 경우를 처리합니다.
User3301

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

대문자 다음에 소문자를 검색해야합니다. 긍정적 인 미리보기는 대문자로 시작하고 소문자가 뒤 따르는 다른 단어를 찾지 만 일치에는 포함하지 않습니다.

여기 봐 : http://regexr.com?30ooo


0

낙타 케이스 형식의 일부 키를 밑줄이있는 소문자로 변환하기 위해 이것을 구현해야했습니다. 내가 생각 해낸 정규식은 다음과 같습니다.

(?<!^|_|[A-Z])([A-Z])

영어에서는 문자열의 시작, 밑줄 또는 다른 대문자가 앞에 나오지 않는 대문자를 나타냅니다 .

아래 샘플에서 굵게 표시된 문자는 앞서 언급 한 정규 표현식을 사용하여 일치를 생성해야하는 문자입니다.

  • Camel C ase T o S omething E lse
  • 낙타 C ase T o S omething E lse
  • camel_case_to_something_else
  • Camel_Case_To_Something_Else
  • CAMEL_CASE_TO_SOMETHING_ELSE

표현식은 이미 소문자 + 밑줄 형식 인 문자열에는 영향을주지 않습니다.

대체 패턴은 다음과 같습니다.

_l$1

즉 , 첫 번째 캡처 그룹의 소문자를 의미 하고 첫 번째 캡처 그룹은 대문자입니다. 나중에 전체 문자열을 소문자로 지정하여 위 목록에서 마지막 두 샘플을 정규화 할 수도 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.