Java regex ที่รวบรวมดัชนีกลุ่ม


113

ฉันมีบรรทัดต่อไปนี้

typeName="ABC:xxxxx;";

ฉันต้องการที่จะดึงข้อมูลคำABC,

ฉันเขียนข้อมูลโค้ดต่อไปนี้

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

ดังนั้นถ้าฉันใส่group(0)ฉันได้รับABC:แต่ถ้าฉันใส่group(1)มันABCฉันก็เลยอยากรู้

  1. นี้จะมีอะไร0และ1หมายความว่าอย่างไร จะดีกว่าถ้าใครสามารถอธิบายฉันด้วยตัวอย่างดีๆ

  2. รูปแบบ regex มี a :อยู่ด้วยเหตุใดgroup(1)ผลลัพธ์จึงละเว้นสิ่งนั้น กลุ่มที่ 1 ตรวจพบคำทั้งหมดในวงเล็บหรือไม่

  3. ดังนั้นถ้าฉันใส่วงเล็บอีกสองอันเช่น\\s*(\d*)(.*): แล้วจะมีสองกลุ่มไหม group(1)จะคืน(\d*)ส่วนและgroup(2)คืน(.*)ส่วนหรือไม่

ข้อมูลโค้ดนี้มีจุดประสงค์เพื่อล้างความสับสนของฉัน ไม่ใช่รหัสที่ฉันกำลังดำเนินการอยู่ รหัสที่ให้ไว้ข้างต้นสามารถทำได้ด้วยString.split()วิธีที่ง่ายกว่ามาก

คำตอบ:


182

การจับภาพและการจัดกลุ่ม

กลุ่มการบันทึก (pattern)จะสร้างกลุ่มที่มีคุณสมบัติการจับภาพ

หนึ่งที่เกี่ยวข้องที่คุณมักจะอาจจะเห็น (และใช้) เป็น(?:pattern)ซึ่งจะสร้างกลุ่มโดยไม่ต้องจับคุณสมบัติชื่อจึงไม่ใช่การจับภาพกลุ่ม

โดยทั่วไปกลุ่มจะใช้เมื่อคุณต้องการทำซ้ำลำดับของรูปแบบเช่น(\.\w+)+หรือเพื่อระบุว่าการสลับควรมีผลอย่างไรเช่น^(0*1|1*0)$( ^จากนั้น0*1หรือ1*0จากนั้น$) เทียบกับ^0*1|1*0$( ^0*1หรือ1*0$)

กลุ่มการจับภาพนอกเหนือจากการจัดกลุ่มจะบันทึกข้อความที่ตรงตามรูปแบบภายในกลุ่มการจับภาพ(pattern)ด้วย โดยใช้ตัวอย่างของคุณ(.*):, .*การแข่งขันABCและ:การแข่งขัน:และตั้งแต่.*อยู่ในการจับภาพกลุ่ม(.*)ข้อความABCจะถูกบันทึกไว้สำหรับกลุ่มจับ 1

หมายเลขกลุ่ม

รูปแบบทั้งหมดถูกกำหนดให้เป็นกลุ่มหมายเลข 0

กลุ่มใดจับภาพในการจัดทำดัชนีเริ่มต้นรูปแบบจาก 1. ดัชนีจะถูกกำหนดโดยคำสั่งของวงเล็บเปิดตัวของกลุ่มจับ ดังตัวอย่างต่อไปนี้คือกลุ่มการจับภาพทั้ง 5 กลุ่มในรูปแบบด้านล่าง:

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

หมายเลขกลุ่มถูกใช้ในการอ้างอิงกลับ\nในรูปแบบและ$nในสตริงการแทนที่

ในรสชาติ regex อื่น ๆ (PCRE, Perl) ยังสามารถใช้ในการโทรแบบย่อยได้

Matcher.group(int group)คุณสามารถเข้าถึงข้อความที่จับคู่โดยบางกลุ่มด้วย หมายเลขกลุ่มสามารถระบุได้ด้วยกฎที่ระบุไว้ข้างต้น

ใน regex บางรสชาติ (PCRE, Perl) มีคุณสมบัติการรีเซ็ตสาขาซึ่งช่วยให้คุณสามารถใช้หมายเลขเดียวกันในการจับกลุ่มในการสลับสาขาต่างๆ

ชื่อกลุ่ม

จาก Java 7 คุณสามารถกำหนดกลุ่มจับชื่อ และคุณสามารถเข้าถึงเนื้อหาที่ตรงกับ(?<name>pattern) Matcher.group(String name)นิพจน์ทั่วไปยาวกว่า แต่โค้ดมีความหมายมากกว่าเนื่องจากระบุสิ่งที่คุณพยายามจับคู่หรือแยกออกด้วยนิพจน์ทั่วไป

ชื่อกลุ่มถูกใช้ในการอ้างอิงย้อนกลับ\k<name>ในรูปแบบและ${name}ในสตริงการแทนที่

Matcher.group(int group)ตั้งชื่อกลุ่มจับยังคงนับเข้ากับโครงร่างลำดับเลขเดียวกันดังนั้นพวกเขายังสามารถเข้าถึงได้ผ่านทาง

ภายในการใช้งาน Java เพียงแค่แมปจากชื่อไปยังหมายเลขกลุ่ม ดังนั้นคุณไม่สามารถใช้ชื่อเดียวกันสำหรับ 2 กลุ่มการจับภาพที่แตกต่างกัน


1
ว้าว! ขอบคุณ @nhahtdh สำหรับการอธิบายกลุ่มที่ไม่ได้จับภาพด้วยวิธีการทำงานของลำดับกลุ่มที่ซ้อนกัน ฉันนิ่งงันกับวิธีการทำงานของหมายเลขกลุ่มจนกระทั่งในที่สุดฉันก็ได้อ่านคำอธิบายของคุณ ขอบคุณมาก!
MMeah

92

สำหรับพวกเราที่เหลือ

นี่คือตัวอย่างง่ายๆและชัดเจนเกี่ยวกับวิธีการทำงานนี้

regex: ([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

สตริง: "!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

อย่างที่คุณเห็นฉันได้สร้างกลุ่มห้ากลุ่มซึ่งแต่ละกลุ่มอยู่ในวงเล็บ

ฉันรวม! * และ *! ด้านใดด้านหนึ่งเพื่อให้ชัดเจนขึ้น โปรดสังเกตว่าไม่มีอักขระเหล่านั้นอยู่ใน RegEx ดังนั้นจึงจะไม่ถูกสร้างในผลลัพธ์ กลุ่ม (0) ให้สตริงที่ตรงกันทั้งหมด (เกณฑ์การค้นหาทั้งหมดของฉันในบรรทัดเดียว) กลุ่ม 1 หยุดก่อนช่องว่างแรกเนื่องจากอักขระช่องว่างไม่รวมอยู่ในเกณฑ์การค้นหา กลุ่ม 2 และ 4 เป็นเพียงช่องว่างสีขาวซึ่งในกรณีนี้คืออักขระช่องว่างอย่างแท้จริง แต่อาจเป็นแท็บหรือฟีดบรรทัดก็ได้เช่นกันกลุ่มที่ 3 มีช่องว่างเนื่องจากฉันใส่ไว้ในเกณฑ์การค้นหา ...

หวังว่านี่จะสมเหตุสมผล


1
ตัวอย่างที่สมบูรณ์แบบที่เข้าใจง่ายสำหรับผู้เริ่มต้น ฉันสงสัยว่านี่เหมือนกับการจัดกลุ่ม reg ex ใน python หรือไม่? หรือมีความแตกต่างหรือไม่? ฉันยังใหม่กับ reg ex นั่นเป็นสาเหตุที่ทำให้ฉันสับสนทั้งสองภาษา
มณี

1
นี่ไม่ใช่ Java regex ที่ถูกต้อง: แบ็กสแลชจะต้องเพิ่มเป็นสองเท่า
Nicolas Raoul

1
@NicolasRaoul: แบ็กสแลชคู่เกิดจากไวยากรณ์ Escape ในสตริงลิเทอรัล ไวยากรณ์ regex จริง (เช่นถ้าคุณพิมพ์สตริงที่มี regex ไปยังคอนโซล) ไม่ต้องใช้แบ็กสแลชคู่
nhahtdh

@NicolasRaoul หากคุณต้องการคัดลอกและวางสตริง regex ของฉันลงในโค้ด java จริงโดยใช้ IDE ที่มีความสามารถ IDE จะจัดรูปแบบเครื่องหมายขีดทับได้อย่างถูกต้องตามต้องการ แต่ Regex ของฉันมีความถูกต้องในทางเทคนิคและทางไวยากรณ์และมีจุดประสงค์หลักเพื่อแสดงให้เห็นถึงความสัมพันธ์ระหว่างโค้ด regex และผลลัพธ์ที่ได้รับ (โดยใช้ตัวอย่างที่เฉพาะเจาะจงมาก) ... ทำให้สว่างขึ้นเล็กน้อย ... ☺
Michael Sims

44

วงเล็บ()ใช้เพื่อเปิดใช้งานการจัดกลุ่มวลี regex

group(1)มีสตริงที่อยู่ระหว่างวงเล็บ(.*)ดังนั้น.*ในกรณีนี้

และgroup(0)มีสตริงที่ตรงกันทั้งหมด

หากคุณมีกลุ่มเพิ่มเติม (อ่าน(...)) ระบบจะจัดกลุ่มที่มีดัชนีถัดไป (2, 3 และอื่น ๆ )


2
ดังนั้นฉันถูกต้องที่การเพิ่มวงเล็บเป็นการสร้างกลุ่มจริงหรือ?
P basak

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