Regex để chuyển đổi CamelCase thành camel_case trong java


86

Tôi hiểu tại sao sản lượng mong muốn không được đưa ra cho việc chuyển đổi sử dụng regex một chuỗi như FooBarđể Foo_Barmà thay vào đó đưa ra Foo_Bar_. Tôi có thể đã làm điều gì đó với String.substring substring(0, string.length() - 2)hoặc chỉ thay thế ký tự cuối cùng, nhưng tôi nghĩ có một giải pháp tốt hơn cho một kịch bản như vậy.

Đây là mã:

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
*/

Câu hỏi: Tìm kiếm một cách gọn gàng hơn để có được đầu ra mong muốn?


Câu hỏi này cũng tương tự như stackoverflow.com/questions/4886091/...
Paul Vargas

Câu trả lời:


168

Xem câu hỏi này và CaseFormattừ ổi

trong trường hợp của bạn, một cái gì đó như:

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

@eliocs câu hỏi không được gắn thẻ android và "cách gọn gàng hơn" .. Dù sao cũng cảm ơn bạn đã downvote;)

2
Liên kết CaseFormat đang ngoại tuyến. Thay thế là ở đây
Anticom

66

ràng buộc chữ thường và chữ hoa thành hai nhóm, nó sẽ ổn

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
Lưu ý: Nếu các từ đơn được cho phép trong Chuỗi đầu vào, ví dụ: "thisIsATest", đoạn mã trên sẽ in ra "this_is_atest". Ổi, trong câu trả lời được chấp nhận, cho kết quả là "this_is_a_test".
DtotheK

Cái này sẽ không làm việc trên một tên bắt đầu với mũ, ví dụ như: IBMIsMyCompany.
Người dùng3301

37

Bạn có thể sử dụng đoạn mã dưới đây:

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

Điều gì sẽ xảy ra nếu chuỗi của tôi chứa một số - mode3 kết thúc là mode3, trong khi tôi muốn mode_3.
Mike Stoddart

Nó không chuyển đổi trường hợp lạc đà như MyUUIDgạch dưới đúng cách, tôi hiểu my_uu_id.
Người dùng3301

6

Tôi không thể cung cấp RegEx, dù sao thì nó cũng sẽ rất phức tạp.

Hãy thử chức năng này với tính năng tự động nhận dạng các từ viết tắt.

Rất tiếc, Guava lib không tự động phát hiện các từ viết tắt chữ hoa, vì vậy "bigCAT" sẽ được chuyển đổi thành "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();
}

4

Tại sao không chỉ cần đối sánh ký tự trước như một ký tự không phải là đầu dòng $?

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

Lưu ý rằng phiên bản này an toàn để thực hiện trên một thứ gì đó đã được bọc bằng vỏ camel.


Bạn đang cố gắng sử dụng ^$làm mỏ neo? Bởi vì ý nghĩa của chúng thay đổi khi bạn đặt chúng vào một lớp ký tự. [^$_A-Z]khớp với bất kỳ nhân vật đó không phải $, _hoặc một ký tự hoa, và tôi không nghĩ rằng đó là những gì bạn có nghĩa là.
Alan Moore

Không có ý định làm mỏ neo, Tôi đang cố gắng không khớp với ký tự trên, ký tự $đã được thêm vào một cách nhầm lẫn vì đó là một kỹ thuật tôi sử dụng trên tên lớp.
Brett Ryan

3

Thêm xác nhận trên đầu nhìn có chiều rộng bằng không.

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

Đọc tài liệu cho (?=X)v.v.

Cá nhân tôi thực sự sẽ chia chuỗi, sau đó kết hợp lại. Điều này thậm chí có thể nhanh hơn khi được thực hiện đúng và nó làm cho mã dễ hiểu hơn nhiều so với phép thuật biểu thức chính quy. Đừng hiểu sai ý tôi: Tôi thích biểu thức chính quy. Nhưng đây không thực sự là một biểu thức chính quy gọn gàng, cũng như việc chuyển đổi này không phải là một tác vụ regexp cổ điển. Sau khi tất cả, có vẻ như bạn cũng muốn làm chữ thường?

Một cách hack xấu xí nhưng nhanh chóng sẽ là thay thế (.)([A-Z]+)bằng $1_$2và sau đó viết thường toàn bộ chuỗi sau đó (trừ khi bạn có thể thực hiện regexps cực đoan kiểu perl, nơi bạn có thể viết thường trực tiếp thay thế!). Tôi vẫn coi việc chia tách ở chuyển tiếp từ dưới lên trên, sau đó chuyển đổi, rồi nối là cách thích hợp và dễ đọc nhất để thực hiện việc này.


Vâng, cuối cùng tôi cũng muốn nó ở dạng chữ thường.
ajmartin

Vì vậy, tôi sẽ chia nó thành các phần phù hợp [A-Z][a-z]*, viết thường chữ cái đầu tiên và nối chúng lại. Hoặc thủ thuật thay thế + viết thường mà tôi vừa thêm vào phần trả lời chính.
Có QUIT - Anony-Mousse,

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 được sử dụng để làm cho nhóm
abinash Sahu

2

Không chắc có thể có thứ gì đó thực sự hòa tan với regex nguyên chất. Đặc biệt là hỗ trợ các từ viết tắt.

Tôi đã tạo một hàm nhỏ, lấy cảm hứng từ câu trả lời @radzimir, hỗ trợ các từ viết tắt và không có ký tự chữ cái:

Từ 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
Đây là một câu trả lời chất lượng, nó xử lý hầu hết các trường hợp cạnh.
Người dùng3301

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

Nên tìm kiếm một ký tự viết hoa theo sau là các ký tự viết thường. Trang đầu tích cực sẽ tìm kiếm một từ khác bắt đầu bằng chữ in hoa theo sau là chữ thường nhưng KHÔNG đưa nó vào kết quả phù hợp.

Xem tại đây: http://regexr.com?30ooo


0

Tôi đã phải triển khai điều này để chuyển đổi một số khóa ở định dạng chữ hoa camel thành chữ thường với dấu gạch dưới. Biểu thức chính quy mà tôi đã nghĩ ra là:

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

Trong tiếng Anh, nó là viết tắt của ký tự viết hoa không đứng trước đầu chuỗi, một dấu gạch dưới hoặc một ký tự viết hoa khác .

Trong các mẫu bên dưới, ký tự in đậm là những ký tự sẽ tạo ra kết quả khớp bằng cách sử dụng biểu thức chính quy nói trên:

  • Lạc đà C ase T o S omething E lse
  • lạc đà C ase T o S omething E lse
  • camel_case_to_something_else
  • Camel_Case_To_Something_Else
  • CAMEL_CASE_TO_SOMETHING_ELSE

Lưu ý rằng biểu thức không ảnh hưởng đến chuỗi đã ở định dạng chữ thường + dấu gạch dưới.

Mẫu thay thế sẽ là:

_l$1

Có nghĩa là viết thường của nhóm bắt đầu tiên, nhóm bắt đầu tiên là chữ cái viết hoa. Bạn cũng có thể viết thường toàn bộ chuỗi sau đó để chuẩn hóa hai mẫu cuối cùng từ danh sách ở trên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.