【问题标题】:How can I count the number of matches for a regex?如何计算正则表达式的匹配数?
【发布时间】:2011-11-14 18:15:08
【问题描述】:

假设我有一个包含以下内容的字符串:

HelloxxxHelloxxxHello

我编译了一个模式来寻找“你好”

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

它应该找到三个匹配项。如何计算有多少匹配项?

我尝试了各种循环并使用matcher.groupCount(),但没有成功。

【问题讨论】:

  • 您的搜索字符串是否有可能在输入字符串中出现重叠?

标签: java regex


【解决方案1】:

matcher.find() 没有找到 所有 个匹配项,只有 下一个 个匹配项。

Java 9+ 解决方案

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

Java 8 及更早版本的解决方案

您必须执行以下操作。 (Starting from Java 9, there is a nicer solution)

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
    }
}

处理重叠匹配

当计算aaaaaa 的匹配时,上面的sn-p 会给你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++; }
【解决方案2】:

从Java 9开始,你可以使用Matcher.results()提供的流

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

【讨论】:

    【解决方案3】:

    使用以下代码查找正则表达式在您的输入中找到的匹配数

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

    这是一个通用代码而不是具体代码,请根据您的需要进行调整

    如有错误欢迎指正。

    【讨论】:

      【解决方案4】:

      这应该适用于可能重叠的匹配:

      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);
      }
      

      【讨论】:

        【解决方案5】:

        如果你想使用 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);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-11-12
          • 2019-05-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多