Regex Named Groups in Java

173

Ini adalah pemahaman saya bahwa java.regexpaket tersebut tidak memiliki dukungan untuk grup bernama ( http://www.regular-expressions.info/named.html ) jadi dapatkah orang mengarahkan saya ke perpustakaan pihak ketiga yang melakukannya?

Saya telah melihat jregex tetapi rilis terakhirnya pada tahun 2002 dan tidak berhasil untuk saya (memang saya hanya mencoba sebentar) di bawah java5.

Dan
sumber
3
Pemahaman Anda salah. JDK7 menangani grup bernama.
tchrist
2
@tchrist Pada tahun 2009 tidak ada JDK7.
Alex78191

Jawaban:

276

( Pembaruan : Agustus 2011 )

Seperti yang disebutkan geofflane dalam jawabannya , Java 7 sekarang mendukung kelompok bernama .
tchrist menunjukkan dalam komentar bahwa dukungan terbatas.
Dia merinci batasan dalam jawaban besarnya " Java Regex Helper "

Java 7 regex bernama dukungan kelompok disajikan kembali pada bulan September 2010 di blog Oracle .

Dalam rilis resmi Java 7, konstruk untuk mendukung grup penangkap bernama adalah:

  • (?<name>capturing text) untuk mendefinisikan grup bernama "nama"
  • \k<name> untuk mereferensi grup "nama" yang diberi nama
  • ${name} untuk referensi ke grup yang ditangkap dalam string pengganti Matcher
  • Matcher.group(String name) untuk mengembalikan input yang ditangkap selanjutnya oleh "grup bernama" yang diberikan.

Alternatif lain untuk pra-Jawa 7 adalah:


( Jawaban asli : Jan 2009 , dengan dua tautan berikutnya sekarang terputus)

Anda tidak dapat merujuk ke grup yang disebutkan, kecuali jika Anda membuat kode versi Regex ...

Itulah tepatnya yang dilakukan Gorbush2 di utas ini .

Regex2

(implementasi terbatas, seperti yang ditunjukkan lagi oleh tchrist , karena hanya terlihat untuk pengidentifikasi ASCII. tchrist merinci batasannya sebagai:

hanya dapat memiliki satu grup bernama per nama yang sama (yang tidak selalu Anda kendalikan!) dan tidak dapat menggunakannya untuk rekursi in-regex.

Catatan: Anda dapat menemukan contoh rekursi regex sejati di Perl dan regex PCRE, sebagaimana disebutkan dalam Regexp Power , spesifikasi PCRE , dan String Pencocokan dengan slide Parentheses Seimbang )

Contoh:

Tali:

"TEST 123"

RegExp:

"(?<login>\\w+) (?<id>\\d+)"

Mengakses

matcher.group(1) ==> TEST
matcher.group("login") ==> TEST
matcher.name(1) ==> login

Menggantikan

matcher.replaceAll("aaaaa_$1_sssss_$2____") ==> aaaaa_TEST_sssss_123____
matcher.replaceAll("aaaaa_${login}_sssss_${id}____") ==> aaaaa_TEST_sssss_123____ 

(ekstrak dari implementasi)

public final class Pattern
    implements java.io.Serializable
{
[...]
    /**
     * Parses a group and returns the head node of a set of nodes that process
     * the group. Sometimes a double return system is used where the tail is
     * returned in root.
     */
    private Node group0() {
        boolean capturingGroup = false;
        Node head = null;
        Node tail = null;
        int save = flags;
        root = null;
        int ch = next();
        if (ch == '?') {
            ch = skip();
            switch (ch) {

            case '<':   // (?<xxx)  look behind or group name
                ch = read();
                int start = cursor;
[...]
                // test forGroupName
                int startChar = ch;
                while(ASCII.isWord(ch) && ch != '>') ch=read();
                if(ch == '>'){
                    // valid group name
                    int len = cursor-start;
                    int[] newtemp = new int[2*(len) + 2];
                    //System.arraycopy(temp, start, newtemp, 0, len);
                    StringBuilder name = new StringBuilder();
                    for(int i = start; i< cursor; i++){
                        name.append((char)temp[i-1]);
                    }
                    // create Named group
                    head = createGroup(false);
                    ((GroupTail)root).name = name.toString();

                    capturingGroup = true;
                    tail = root;
                    head.next = expr(tail);
                    break;
                }
VONC
sumber
kedua tautan di atas nampaknya rusak?
Jonas
Kode ini bermasalah. Ia sedang mencari pengidentifikasi ASCII. Itu salah. Seharusnya mencari apa pun yang memungkinkan Java dalam pengidentifikasi !!
tchrist
1
Hanya FYI karena Anda tampaknya sangat teliti, bagian terbatas tidak begitu banyak tentang nama-nama ASCII vs Unicode karena hanya mampu memiliki satu grup bernama per nama yang sama (yang Anda tidak selalu memiliki kendali atas!) Dan tidak bisa menggunakannya untuk rekursi in-regex.
tchrist
@tchrist: terima kasih atas ketepatan ini (termasuk). Saya juga telah menambahkan tautan kembali ke jawaban bintang Anda di "Java Regex helper" (upvoted).
VonC
Tidak ada metode matcher.name (int index) untuk objek Matcher di Jawa ??
OT0
27

Ya tapi itu berantakan peretasan kelas matahari. Ada cara yang lebih sederhana:

http://code.google.com/p/named-regexp/

named-regexp adalah pembungkus tipis untuk implementasi ekspresi reguler standar JDK, dengan tujuan tunggal menangani grup penangkap bernama dalam gaya .net: (? ...).

Ini dapat digunakan dengan Java 5 dan 6 (generik digunakan).

Java 7 akan menangani kelompok penangkap bernama, jadi proyek ini tidak dimaksudkan untuk bertahan lama.

John Hardy
sumber
1
Sayang sekali ini tidak dapat digunakan dari dalam GWT.
Sakuraba
4
Lihat garpu GitHub dari proyek ini, yang memperbaiki beberapa bug dari aslinya. Itu juga diselenggarakan di Maven Central.
tony19
1
Hanya kata hati-hati dalam kasus saya, garpu tony19 di Github tidak berfungsi di Android pada 0.1.8.
Chuck D
2
@RubberMallet, Masalah khusus Android kini telah diperbaiki dan akan berada di 0.1.9.
tony19
2

Masalah apa yang Anda dapatkan dengan jregex ? Ini bekerja dengan baik untuk saya di bawah java5 dan java6.

Jregex melakukan pekerjaan dengan baik (bahkan jika versi terakhir adalah dari tahun 2002), kecuali jika Anda ingin menunggu javaSE 7 .

Brian Clozel
sumber
2

Bagi mereka yang menjalankan pre-java7, grup yang diberi nama didukung oleh joni (port Java pada pustaka regigur Oniguruma ). Dokumentasi jarang, tetapi telah bekerja dengan baik untuk kita.
Binari tersedia melalui Maven ( http://repository.codehaus.org/org/jruby/joni/joni/ ).

Ryan Smith
sumber
Saya sangat tertarik dengan opsi joni yang disebutkan oleh Ryan di atas - apakah Anda memiliki cuplikan kode menggunakan kelompok tangkapan bernama - Saya telah berhasil mendapatkan pencocokan dasar dan pencarian agar berfungsi dengan benar - tetapi saya tidak melihat metode mana yang akan saya gunakan untuk dapatkan akses ke nama grup atau untuk mendapatkan nilai tangkapan menggunakan nama grup.
malsmith
1

Sebuah pertanyaan yang agak lama tapi saya mendapati diri saya membutuhkan ini juga dan bahwa saran di atas tidak memadai - dan karenanya - mengembangkan bungkus tipis sendiri: https://github.com/hofmeister/MatchIt

Henrik Hofmeister
sumber