Як я можу підрахувати кількість збігів за регулярний вираз?


97

Скажімо, у мене є рядок, який містить це:

HelloxxxHelloxxxHello

Я складаю шаблон для пошуку "Привіт"

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

Слід знайти три поєдинки. Як я можу підрахувати кількість матчів?

Я спробував різні цикли і використовував, matcher.groupCount()але це не вийшло.


Будь-який шанс, що ваш рядок пошуку може мати збіги у вхідному рядку?
aioobe

Відповіді:


177

matcher.find()знаходить не всі збіги, лише наступний збіг.

Рішення для Java 9+

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

Рішення для Java 8 та новіших версій

Вам доведеться зробити наступне. ( Починаючи з Java 9, є приємніше рішення )

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

До речі, 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++; }
Мукеш Кумар Гупта

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

Використовуйте код нижче, щоб знайти кількість збігів, які регулярний вираз знаходить у вашому введенні

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

Це узагальнений код, не конкретний, однак, адаптуйте його відповідно до ваших потреб

Будь ласка, не соромтеся виправити мене, якщо є якась помилка.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.