Regex untuk mengubah CamelCase menjadi camel_case di java

86

Saya mengerti mengapa output yang diinginkan tidak diberikan untuk mengkonversi menggunakan regex string seperti FooBaruntuk Foo_Baryang bukan memberi Foo_Bar_. Saya bisa saja melakukan sesuatu dengan String.substring substring(0, string.length() - 2)atau hanya mengganti karakter terakhir, tetapi saya pikir ada solusi yang lebih baik untuk skenario seperti itu.

Ini kodenya:

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

Pertanyaan: Mencari cara yang lebih rapi untuk mendapatkan hasil yang diinginkan?

ajmartin
sumber
Pertanyaan ini mirip dengan stackoverflow.com/questions/4886091/…
Paul Vargas

Jawaban:

171

Lihat pertanyaan ini dan CaseFormatdari jambu biji

dalam kasus Anda, sesuatu seperti:

CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");
mkobit
sumber
@eliocs pertanyaannya tidak diberi tag android dan "cara yang lebih rapi" .. Terima kasih atas downvote-nya;)
2
Tautan CaseFormat sedang offline. Penggantian ada di sini
Anticom
66

ikat huruf kecil dan huruf besar sebagai dua kelompok, itu akan baik-baik saja

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());
    }
}
clevertension
sumber
2
Catatan: Jika kata satu huruf diizinkan dalam String input, misalnya "thisIsATest", kode di atas akan mencetak "this_is_atest". Guava, dalam jawaban yang diterima, menghasilkan "this_is_a_test".
DtotheK
Yang satu ini tidak akan bekerja pada nama mulai dengan topi, misalnya: IBMIsMyCompany.
Pengguna3301
37

Anda dapat menggunakan potongan kode di bawah ini:

String replaceAll = key.replaceAll("(.)(\\p{Upper})", "$1_$2").toLowerCase();
Sandeep Vaid
sumber
Bagaimana jika string saya berisi angka - mode3 berakhir sebagai mode3, sedangkan saya menginginkan mode_3.
Mike Stoddart
Itu tidak mengubah kasus unta seperti MyUUIDmenggarisbawahi dengan benar, saya mengerti my_uu_id.
Pengguna3301
6

Saya tidak bisa memberikan RegEx, itu akan menjadi sangat rumit.

Coba fungsi ini dengan pengenalan akronim otomatis.

Sayangnya Guava lib tidak otomatis mendeteksi akronim huruf besar, jadi "bigCAT" akan diubah menjadi "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();
}
radzimir.dll
sumber
5

Mengapa tidak mencocokkan karakter sebelumnya saja sebagai awal baris $?

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

Perhatikan bahwa versi ini aman untuk dilakukan pada sesuatu yang sudah bertangkai unta.

Brett Ryan
sumber
Apakah Anda mencoba menggunakan ^dan $sebagai jangkar? Karena artinya berubah ketika Anda menempatkannya di kelas karakter. [^$_A-Z]cocok dengan karakter apa pun yang bukan $,, _atau huruf besar, dan menurut saya bukan itu yang Anda maksud.
Alan Moore
Tidak bermaksud sebagai jangkar, Saya mencoba untuk tidak mencocokkan karakter atas, $itu secara keliru ditambahkan karena ini adalah teknik yang saya gunakan pada nama kelas.
Brett Ryan
3

Tambahkan pernyataan kepala tampilan lebar-nol.

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

Baca dokumentasi untuk (?=X) dll.

Secara pribadi, saya benar-benar akan membagi string, lalu menggabungkannya kembali. Ini bahkan mungkin lebih cepat bila dilakukan dengan benar, dan membuat kode lebih mudah dipahami daripada sihir ekspresi reguler. Jangan salah paham: Saya suka ekspresi reguler. Tapi ini bukanlah ekspresi reguler yang rapi, juga bukan transformasi ini tugas regexp klasik. Toh sepertinya Anda juga ingin melakukan huruf kecil?

Peretasan yang jelek tapi cepat adalah mengganti (.)([A-Z]+)dengan $1_$2dan kemudian huruf kecil seluruh string sesudahnya (kecuali jika Anda dapat melakukan regexps ekstrend gaya-perl, di mana Anda dapat mengecilkan pengganti secara langsung!). Masih saya pertimbangkan untuk memisahkan pada transisi bawah-ke-atas, lalu mentransformasikannya, lalu bergabung sebagai cara yang tepat dan paling mudah dibaca untuk melakukan ini.

Memiliki QUIT - Anony-Mousse
sumber
Ya, akhirnya saya juga ingin menggunakan huruf kecil.
ajmartin
Jadi saya akan membaginya menjadi potongan-potongan yang cocok [A-Z][a-z]*, huruf kecil huruf pertama, dan menggabungkannya kembali. Atau trik penggantian + huruf kecil yg baru saja saya tambahkan pada main yg utama.
Memiliki 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);  
    }
}
abinash sahu
sumber
$ 1-digunakan untuk membuat grup
abinash sahu
2

Tidak yakin mungkin memiliki sesuatu yang benar-benar solide dengan ekspresi reguler. Terutama untuk mendukung akronim.

Saya telah membuat fungsi kecil, terinspirasi oleh jawaban @radzimir, yang mendukung akronim dan tanpa karakter alfabet:

Dari 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();
}
Thomas Decaux
sumber
1
Ini adalah jawaban yang berkualitas, ini menangani sebagian besar kasus tepi.
Pengguna3301
1
([A-Z][a-z\d]+)(?=([A-Z][a-z\d]+))

Harus mencari huruf kapital diikuti dengan huruf kecil. Orang yang melihat dengan positif akan mencari kata lain yang dimulai dengan huruf kapital diikuti dengan huruf kecil tetapi TIDAK akan memasukkannya ke dalam pertandingan.

Lihat di sini: http://regexr.com?30ooo

Mendongkrak
sumber
0

Saya harus menerapkan ini untuk mengonversi beberapa kunci dalam format huruf unta menjadi huruf kecil dengan garis bawah. Ekspresi reguler yang saya temukan adalah:

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

Dalam bahasa Inggris singkatan dari huruf kapital yang tidak didahului dengan awal string, garis bawah atau huruf kapital lainnya. .

Pada contoh di bawah, karakter yang dicetak tebal adalah yang harus menghasilkan kecocokan menggunakan ekspresi reguler yang disebutkan di atas:

  • Unta C ase T o S omething E lse
  • unta C ase T o S omething E lse
  • camel_case_to_something_else
  • Camel_Case_To_Something_Else
  • CAMEL_CASE_TO_SOMETHING_ELSE

Perhatikan ekspresi tidak mempengaruhi string yang sudah dalam format huruf kecil + garis bawah.

Pola penggantiannya adalah:

_l$1

Yang berarti huruf kecil dari kelompok penangkap pertama, kelompok penangkap pertama adalah huruf kapital. Anda dapat menurunkan huruf kecil seluruh string setelah itu juga untuk menormalkan dua sampel terakhir dari daftar di atas.

argenkiwi
sumber