ฉันจะนับจำนวนการจับคู่สำหรับ regex ได้อย่างไร


101

สมมติว่าฉันมีสตริงที่ประกอบด้วยสิ่งนี้:

HelloxxxHelloxxxHello

ฉันรวบรวมรูปแบบเพื่อค้นหา 'สวัสดี'

Pattern pattern = Pattern.compile("Hello");
Matcher matcher = pattern.matcher("HelloxxxHelloxxxHello");

มันควรจะพบสามการแข่งขัน ฉันจะนับจำนวนการแข่งขันได้อย่างไร?

ฉันได้ลองใช้ลูปต่างๆแล้วmatcher.groupCount()แต่มันไม่ได้ผล


มีโอกาสที่สตริงการค้นหาของคุณอาจเกิดการทับซ้อนกันในสตริงอินพุตหรือไม่?
aioobe

คำตอบ:


181

matcher.find()ไม่พบการแข่งขันทั้งหมดเฉพาะนัดถัดไป

โซลูชันสำหรับ Java 9+

long matches = matcher.results().count();

โซลูชันสำหรับ Java 8 และเก่ากว่า

คุณจะต้องทำสิ่งต่อไปนี้ ( เริ่มจาก Java 9 มีโซลูชันที่ดีกว่า )

int count = 0;
while (matcher.find())
    count++;

Btw matcher.groupCount()เป็นสิ่งที่แตกต่างอย่างสิ้นเชิง

ตัวอย่างที่สมบูรณ์ :

import java.util.regex.*;

class Test {
    public static void main(String[] args) {
        String hello = "HelloxxxHelloxxxHello";
        Pattern pattern = Pattern.compile("Hello");
        Matcher matcher = pattern.matcher(hello);

        int count = 0;
        while (matcher.find())
            count++;

        System.out.println(count);    // prints 3
    }
}

การจัดการการแข่งขันที่ทับซ้อนกัน

เมื่อนับการแข่งขันของaaในaaaaตัวอย่างข้อมูลดังกล่าวข้างต้นจะทำให้คุณ2

aaaa
aa
  aa

เพื่อให้ได้ 3 แมตช์นั่นคือพฤติกรรมนี้:

aaaa
aa
 aa
  aa

คุณต้องค้นหาคู่ที่ดัชนี<start of last match> + 1ดังต่อไปนี้:

String hello = "aaaa";
Pattern pattern = Pattern.compile("aa");
Matcher matcher = pattern.matcher(hello);

int count = 0;
int i = 0;
while (matcher.find(i)) {
    count++;
    i = matcher.start() + 1;
}

System.out.println(count);    // prints 3

การนับจำนวนการจับคู่ที่เกิดขึ้นภายในสตริง วิธี java.util.regex.Matcher.region (int start, int end) ตั้งค่าขีด จำกัด ของภูมิภาคของตัวจับคู่นี้ ภูมิภาคเป็นส่วนของลำดับการป้อนข้อมูลที่จะถูกค้นหาเพื่อค้นหารายการที่ตรงกัน การเรียกใช้เมธอดนี้จะรีเซ็ตตัวจับคู่จากนั้นตั้งค่าภูมิภาคเพื่อเริ่มต้นที่ดัชนีที่ระบุโดยพารามิเตอร์ start และสิ้นสุดที่ดัชนีที่ระบุโดยพารามิเตอร์ end ลองทำตามนี้ while(matcher.find()){ matcher.region(matcher.end()-1, str.length()); count++; }
Mukesh Kumar Gupta

17

สิ่งนี้ควรใช้ได้กับการจับคู่ที่อาจทับซ้อนกัน:

public static void main(String[] args) {
    String input = "aaaaaaaa";
    String regex = "aa";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(input);
    int from = 0;
    int count = 0;
    while(matcher.find(from)) {
        count++;
        from = matcher.start() + 1;
    }
    System.out.println(count);
}


3

หากคุณต้องการใช้สตรีม Java 8 และแพ้whileลูปคุณสามารถลองสิ่งนี้:

public static int countPattern(String references, Pattern referencePattern) {
    Matcher matcher = referencePattern.matcher(references);
    return Stream.iterate(0, i -> i + 1)
            .filter(i -> !matcher.find())
            .findFirst()
            .get();
}

ข้อจำกัดความรับผิดชอบ: ใช้ได้เฉพาะกับการแข่งขันที่ไม่ปะติดปะต่อ

ตัวอย่าง:

public static void main(String[] args) throws ParseException {
    Pattern referencePattern = Pattern.compile("PASSENGER:\\d+");
    System.out.println(countPattern("[ \"PASSENGER:1\", \"PASSENGER:2\", \"AIR:1\", \"AIR:2\", \"FOP:2\" ]", referencePattern));
    System.out.println(countPattern("[ \"AIR:1\", \"AIR:2\", \"FOP:2\" ]", referencePattern));
    System.out.println(countPattern("[ \"AIR:1\", \"AIR:2\", \"FOP:2\", \"PASSENGER:1\" ]", referencePattern));
    System.out.println(countPattern("[  ]", referencePattern));
}

สิ่งนี้พิมพ์ออกมา:

2
0
1
0

นี่เป็นวิธีแก้ปัญหาสำหรับการจับคู่ที่ไม่ปะติดปะต่อกับสตรีม:

public static int countPattern(String references, Pattern referencePattern) {
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
            new Iterator<Integer>() {
                Matcher matcher = referencePattern.matcher(references);
                int from = 0;

                @Override
                public boolean hasNext() {
                    return matcher.find(from);
                }

                @Override
                public Integer next() {
                    from = matcher.start() + 1;
                    return 1;
                }
            },
            Spliterator.IMMUTABLE), false).reduce(0, (a, c) -> a + c);
}

1

ใช้รหัสด้านล่างเพื่อค้นหาจำนวนการจับคู่ที่ regex พบในข้อมูลที่คุณป้อน

        Pattern p = Pattern.compile(regex, Pattern.MULTILINE | Pattern.DOTALL);// "regex" here indicates your predefined regex.
        Matcher m = p.matcher(pattern); // "pattern" indicates your string to match the pattern against with
        boolean b = m.matches();
        if(b)
        count++;
        while (m.find())
        count++;

นี่เป็นรหัสทั่วไปที่ไม่เฉพาะเจาะจง แต่ปรับแต่งให้เหมาะกับความต้องการของคุณ

โปรดอย่าลังเลที่จะแก้ไขฉันหากมีข้อผิดพลาดใด ๆ

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