Как я могу подсчитать количество совпадений для регулярного выражения?
Допустим, у меня есть строка, которая содержит это:
HelloxxxHelloxxxHello
Я компилирую шаблон для поиска 'Hello'
Pattern pattern = Pattern.compile("Hello");Matcher matcher = pattern.matcher("HelloxxxHelloxxxHello");
Должно быть найдено три совпадения. Как я могу подсчитать, сколько совпадений было?
Я пробовал различные циклы и использовал matcher.groupCount() но это не сработало.
matcher.groupCount()
Переведено автоматически
Ответ 1
matcher.find() не находит все совпадения, только следующее совпадение.
matcher.find()
long matches = matcher.results().count();
Вам нужно будет сделать следующее. (Начиная с 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 in aaaa приведенный выше фрагмент даст вам 2.
aa
aaaa
aaaaaa aa
Чтобы получить 3 совпадения, т.е. Такое поведение:
aaaaaa aa aa
Вы должны искать совпадение по индексу <start of last match> + 1 следующим образом:
<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
Ответ 2
Это должно сработать для совпадений, которые могут перекрываться:
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 9, вы можете использовать поток, предоставляемый Matcher.results()
Matcher.results()
Ответ 4
Если вы хотите использовать потоки Java 8 и у вас аллергия на while циклы, вы могли бы попробовать это:
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));}
Это выводит:
2010
Это решение для непересекающихся совпадений с потоками:
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);}