กลุ่มการจับ Java Regex


170

ฉันพยายามที่จะเข้าใจรหัสบล็อกนี้ ในอันแรกสิ่งที่เรากำลังมองหาในการแสดงออกคืออะไร?

ความเข้าใจของฉันคือว่ามันเป็นตัวละครใด ๆ (0 หรือมากกว่าครั้ง *) ตามด้วยหมายเลขใด ๆ ระหว่าง 0 และ 9 (หนึ่งหรือมากกว่าหนึ่งครั้ง +) ตามด้วยตัวละครใด ๆ (0 หรือมากกว่าครั้ง *)

เมื่อสิ่งนี้ถูกดำเนินการผลลัพธ์คือ:

Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0

ใครช่วยกรุณาผ่านสิ่งนี้กับฉันได้ไหม

ข้อดีของการใช้กลุ่มการบันทึกคืออะไร

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTut3 {

    public static void main(String args[]) {
        String line = "This order was placed for QT3000! OK?"; 
        String pattern = "(.*)(\\d+)(.*)";

        // Create a Pattern object
        Pattern r = Pattern.compile(pattern);

        // Now create matcher object.
        Matcher m = r.matcher(line);

        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }

}

1
หากต้องการแทรกบรรทัดใหม่ให้วางช่องว่าง 2 ช่องที่ท้ายบรรทัด เพิ่มเติมเกี่ยวกับไวยากรณ์ของ markdown: en.wikipedia.org/wiki/Markdown - ดูเพิ่มเติมได้ที่: stackoverflow.com/editing-help
assylias

คำตอบ:


248

ปัญหาที่คุณมีอยู่กับประเภทของปริมาณ คุณกำลังใช้ปริมาณโลภในกลุ่มแรกของคุณ (ดัชนี1 - ดัชนี 0 หมายถึงทั้งหมดPattern) ซึ่งหมายความว่ามันจะจับคู่มากที่สุดเท่าที่จะทำได้ (และเนื่องจากเป็นอักขระใด ๆมันจะจับคู่อักขระให้มากที่สุดเท่าที่มี เพื่อให้บรรลุเงื่อนไขสำหรับกลุ่มถัดไป)

ในระยะสั้นกลุ่มที่ 1 ของคุณ .*จับคู่อะไรก็ได้ตราบใดที่กลุ่มถัดไป\\d+สามารถจับคู่บางสิ่งได้ (ในกรณีนี้คือตัวหลักสุดท้าย)

ตามกลุ่มที่ 3 มันจะจับคู่อะไรก็ได้หลังจากตัวเลขสุดท้าย

หากคุณเปลี่ยนเป็นปริมาณที่ไม่เต็มใจในกลุ่มที่ 1 ของคุณคุณจะได้รับผลลัพธ์ที่ฉันคิดว่าคุณคาดหวังนั่นคือส่วนที่3000

จดเครื่องหมายคำถามในกลุ่มที่ 1

String line = "This order was placed for QT3000! OK?";
Pattern pattern = Pattern.compile("(.*?)(\\d+)(.*)");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
    System.out.println("group 1: " + matcher.group(1));
    System.out.println("group 2: " + matcher.group(2));
    System.out.println("group 3: " + matcher.group(3));
}

เอาท์พุท:

group 1: This order was placed for QT
group 2: 3000
group 3: ! OK?

ข้อมูลเพิ่มเติมเกี่ยวกับ Java ที่นี่Pattern

ในที่สุดกลุ่มการจับภาพจะถูกคั่นด้วยวงเล็บเหลี่ยมและเป็นวิธีที่มีประโยชน์มากในการใช้การอ้างอิงย้อนกลับ (เหนือสิ่งอื่นใด) เมื่อคุณPatternจับคู่กับอินพุตแล้ว

ในกลุ่ม Java 6 สามารถอ้างอิงได้โดยคำสั่งของพวกเขาเท่านั้น (ระวังกลุ่มที่ซ้อนกัน

ใน Java 7 นั้นง่ายกว่ามากเพราะคุณสามารถใช้กลุ่มที่มีชื่อ


ขอบคุณ! คือเหตุผลที่กลุ่ม 2 จัดเก็บ 0 เพราะทั้งสายถูกใช้โดยตัวชี้วัดโลภซึ่งสำรองไว้จนกว่ามันจะเข้ามาติดต่อกับตัวเลขหนึ่งตัวหรือมากกว่า 0 พอใจสิ่งนี้ดังนั้นการแสดงออกจึงประสบความสำเร็จ ฉันพบว่ากลุ่มที่สามเกิดความสับสนปริมาณโลภนั้นก็กินทั้งบรรทัด แต่กลับปิดจนกว่าจะพบตัวเลขหนึ่งตัวหรือมากกว่า (\\ d +) ซึ่งควรจะนำหน้าหรือไม่
Xivilai

@ Xivilai ให้ฉันปรับคำอธิบายของฉันในคำตอบของฉันเพียงไม่กี่วินาที
Mena

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

@ Xivilai มากหรือน้อย มันเริ่มต้นจากด้านซ้ายเสมอในกรณีนี้ นี่คือข้อมูลเพิ่มเติมเกี่ยวกับตัวปริมาณ
Mena

2
คุณสามารถใช้กลุ่มจับชื่ออยู่ใน Java 5/6 named-regexpกับ

16

มันก็โอเคเลย

  1. กลุ่มแรก ( m.group(0)) จะจับภาพพื้นที่ทั้งหมดที่อยู่ในนิพจน์ปกติของคุณเสมอพื้นที่ทั้งหมดที่ถูกปกคลุมด้วยการแสดงออกปกติของคุณในกรณีนี้มันเป็นสตริงทั้งหมด
  2. นิพจน์ทั่วไปมีความโลภโดยค่าเริ่มต้นหมายความว่ากลุ่มแรกจะจับภาพได้มากที่สุดโดยไม่ละเมิด regex (.*)(\\d+)(ส่วนแรกของ regex ของคุณ) ครอบคลุม...QT300int กลุ่มแรกและ0ในครั้งที่สอง
  3. คุณได้อย่างรวดเร็วสามารถแก้ไขปัญหานี้โดยการทำให้กลุ่มแรกไม่โลภ: การเปลี่ยนแปลงไป(.*)(.*?)

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับโลภและขี้เกียจตรวจสอบเว็บไซต์นี้


4

จากเอกสาร:

Capturing groups</a> are indexed from left
 * to right, starting at one.  Group zero denotes the entire pattern, so
 * the expression m.group(0) is equivalent to m.group().

ดังนั้นการจับภาพกลุ่ม 0 จึงส่งทั้งเส้น


3

ความเข้าใจของคุณถูกต้อง อย่างไรก็ตามถ้าเราเดินผ่าน:

  • (.*) จะกลืนสายทั้งหมด;
  • มันจะต้องให้กลับอักขระเพื่อที่(\\d+)satistifed (ซึ่งเป็นเหตุผลที่0ถูกจับและไม่3000 );
  • สุดท้าย(.*)จะจับส่วนที่เหลือ

ฉันไม่แน่ใจว่าเจตนาดั้งเดิมของผู้แต่งเป็นอย่างไร

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