Regex Named Groups ใน Java


173

ฉันเข้าใจว่าjava.regexแพคเกจไม่รองรับกลุ่มที่มีชื่อ ( http://www.regular-expressions.info/named.html ) ดังนั้นทุกคนจะสามารถชี้ให้ฉันไปยังห้องสมุดบุคคลที่สามที่ใช่หรือไม่

ฉันดูที่jregexแต่รุ่นล่าสุดของมันคือในปี 2002 และมันไม่ได้ผลสำหรับฉัน (ยอมรับได้ว่าฉันลองใช้สั้น ๆ ) ภายใต้ java5


3
ความเข้าใจของคุณไม่ถูกต้อง JDK7 จัดการกลุ่มที่มีชื่อ
tchrist

2
@tchrist ในปี 2009 ไม่มี JDK7
Alex78191

คำตอบ:


275

( อัปเดต : สิงหาคม 2554 )

ในฐานะที่เป็นgeofflaneกล่าวถึงในคำตอบของเขา , Java 7 ในขณะนี้สนับสนุนกลุ่มชื่อ
tchristชี้ให้เห็นในความคิดเห็นว่าการสนับสนุนมี จำกัด
เขาให้รายละเอียดข้อ จำกัด ในคำตอบที่ยอดเยี่ยม " Java Regex Helper "

Java 7 regex สนับสนุนการตั้งชื่อกลุ่มที่ถูกนำเสนอกลับมาในกันยายน 2010ในบล็อกของออราเคิล

ใน Java 7 รีลีสอย่างเป็นทางการโครงสร้างเพื่อสนับสนุนกลุ่มการดักจับที่ระบุชื่อคือ:

  • (?<name>capturing text) เพื่อกำหนดกลุ่มชื่อ "ชื่อ"
  • \k<name> เพื่อ backreference กลุ่ม "name" ที่มีชื่อ
  • ${name} อ้างอิงถึงกลุ่มที่ถูกจับในสตริงการแทนที่ของ Matcher
  • Matcher.group(String name) เพื่อส่งกลับลำดับที่ถูกบันทึกโดย "กลุ่มที่มีชื่อ" ที่กำหนด

ทางเลือกอื่นสำหรับ pre-Java 7คือ:


( คำตอบดั้งเดิม : ม.ค. 2009โดยมีลิงก์สองลิงก์เสีย)

คุณไม่สามารถอ้างถึงกลุ่มที่มีชื่อเว้นแต่ว่าคุณจะรหัส Regex เวอร์ชันของคุณเอง ...

นั่นคือสิ่งที่Gorbush2 ทำในหัวข้อนี้

Regex2

(การใช้งานที่ จำกัด ตามที่tchristชี้ให้เห็นอีกครั้งเนื่องจากเป็นเพียงตัวระบุ ASCII เท่านั้น tchrist มีรายละเอียดข้อ จำกัด ดังนี้:

ความสามารถในการมีกลุ่มที่มีชื่อหนึ่งกลุ่มต่อชื่อเดียวกันเท่านั้น (ซึ่งคุณไม่สามารถควบคุมได้เสมอ!) และไม่สามารถใช้พวกเขาสำหรับการเรียกซ้ำแบบ in-regex

หมายเหตุ: คุณสามารถค้นหาตัวอย่างการเรียกซ้ำที่แท้จริงของ regex ใน Perl และ PCRE regexes ตามที่กล่าวไว้ในRegexp Power , ข้อมูลจำเพาะ PCREและการจับคู่สตริงที่มีสไลด์ที่สมดุลวงเล็บ )

ตัวอย่าง:

สตริง:

"TEST 123"

นิพจน์ทั่วไป:

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

เข้าไป

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

แทนที่

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

(สารสกัดจากการใช้งาน)

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

ดูเหมือนว่าลิงก์ทั้งสองข้างบนจะใช้งานไม่ได้หรือ
Jonas

รหัสนี้เป็นรถ มันกำลังมองหาตัวระบุ ASCII มันผิด ควรมองหาสิ่งที่ Java อนุญาตในตัวระบุ !!
tchrist

1
เพียงแค่ FYI เนื่องจากคุณดูเหมือนเป็นคนที่เข้าใจดีส่วนที่ จำกัด ไม่มากนักเกี่ยวกับชื่อ ASCII vs Unicode เพราะมันเกี่ยวกับความสามารถในการมีกลุ่มชื่อหนึ่งกลุ่มต่อชื่อเดียวกันเท่านั้น (ซึ่งคุณไม่สามารถควบคุมได้เสมอ!) และ ไม่สามารถใช้งานได้สำหรับการเรียกซ้ำแบบ in-regex
tchrist

@tchrist: ขอบคุณสำหรับความแม่นยำนี้ (รวมอยู่ด้วย) ฉันได้เพิ่มลิงก์กลับไปยังคำตอบที่เป็นตัวเอกของคุณใน "Java Regex helper" (upvoted)
VonC

ไม่มีวิธี matcher.name (ดัชนีดัชนี) สำหรับวัตถุ Matcher ใน Java ??
ot0


27

ใช่ แต่ยุ่งกับการเรียนวิชาดวงอาทิตย์ มีวิธีที่ง่ายกว่า:

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

named-regexp เป็น wrapper แบบบางสำหรับการใช้งานนิพจน์ปกติของ JDK มาตรฐานโดยมีวัตถุประสงค์เพื่อจัดการกลุ่มการจับภาพที่ระบุชื่อในสไตล์. net: (? ... )

มันสามารถใช้กับ Java 5 และ 6 (มีการใช้ข้อมูลทั่วไป)

Java 7 จะจัดการกับกลุ่มการดักจับที่มีชื่อดังนั้นโครงการนี้ไม่ได้มีความสำคัญ


1
แย่มากที่ไม่สามารถใช้งานได้จากภายใน GWT
Sakuraba

4
ลองใช้GitHub forkของโปรเจ็กต์นี้ซึ่งแก้ไขบั๊กหลายตัวจากต้นฉบับ มันยังเป็นเจ้าภาพใน Maven Central
tony19

1
เพียงแค่คำเตือนในกรณีของฉัน tony19 fork บน Github ไม่ทำงานบน Android ตั้งแต่ 0.1.8
Chuck D

2
@RubberMallet ปัญหาเฉพาะ Android ได้รับการแก้ไขแล้วและจะอยู่ใน 0.1.9
tony19


2

สำหรับผู้ที่รัน pre-java7 กลุ่มที่มีชื่อรองรับโดยjoni (พอร์ต Java ของไลบรารี Oniguruma regexp) เอกสารนั้นกระจัดกระจาย แต่ทำงานได้ดีสำหรับเรา
มีให้บริการไบนารีผ่าน Maven ( http://repository.codehaus.org/org/jruby/joni/joni/ )


ฉันสนใจตัวเลือก joni ที่กล่าวถึงโดย Ryan ด้านบน - คุณมีข้อมูลโค้ดใดบ้างโดยใช้กลุ่มการจับภาพที่มีชื่อ - ฉันได้รับการจับคู่ขั้นพื้นฐานและค้นหาการทำงานอย่างถูกต้อง - แต่ฉันไม่เห็นวิธีที่ฉันจะใช้ รับสิทธิ์เข้าถึง groupNames หรือเพื่อรับค่าการดักจับโดยใช้ชื่อกลุ่ม
malsmith

1

คำถามเก่า ๆ แต่ฉันพบว่าตัวเองต้องการสิ่งนี้และข้อเสนอแนะด้านบนนั้นไม่เพียงพอ - และเช่นนั้น - พัฒนาเสื้อคลุมบาง ๆ ด้วยตนเอง: https://github.com/hofmeister/MatchIt

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.