{"record":{"id":"b7a5c7020535ba46","repo":"languagetool-org/languagetool","slug":"got-matcher-groupcount-groups-for-regex","errorCode":null,"errorMessage":"Got \" + matcher.groupCount() + \" groups for regex '\" + pattern.pattern() + \"', expected 1","messagePattern":"Got \" \\+ matcher\\.groupCount\\(\\) \\+ \" groups for regex '\" \\+ pattern\\.pattern\\(\\) \\+ \"', expected 1","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/PartialPosTagFilter.java","lineNumber":81,"sourceCode":"    boolean two_groups_regexp = args.containsKey(\"two_groups_regexp\");\n\n      String prefix = \"\";\n      String suffix = \"\";\n\n      if (args.containsKey(\"prefix\")) {\n          prefix = args.get(\"prefix\");\n      };\n\n      if (args.containsKey(\"suffix\")) {\n          suffix = args.get(\"suffix\");\n      };\n\n     \n    String token = prefix + patternTokens[tokenPos - 1].getToken() + suffix;\n    \n    Matcher matcher = pattern.matcher(token);\n    if ((matcher.groupCount() != 1) && !(two_groups_regexp)) {\n      throw new RuntimeException(\"Got \" + matcher.groupCount() + \" groups for regex '\" + pattern.pattern() + \"', expected 1\");\n    }\n    if ((matcher.groupCount() != 2) && (two_groups_regexp)) {\n      throw new RuntimeException(\"Got \" + matcher.groupCount() + \" groups for regex '\" + pattern.pattern() + \"', expected 2\");\n    }\n    if (matcher.matches()) {\n      String partialToken = matcher.group(1);\n      if (matcher.groupCount() == 2) {\n        partialToken += matcher.group(2);\n      } \n      List<AnalyzedTokenReadings> tags = tag(partialToken);\n      if (tags != null && partialTagHasRequiredTag(tags, requiredTagRegexp, negatePos)) {\n        return match;\n      }\n      return null;\n    }\n    return null;\n  }\n","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/PartialPosTagFilter.java#L63-L99","documentation":"PartialPosTagFilter expects its 'regexp' to contain exactly one capturing group (the part of the token to keep), unless two_groups_regexp is set. This RuntimeException is thrown when the compiled regex's groupCount() != 1 while two_groups_regexp is false.","triggerScenarios":"Setting filter arg regexp to a pattern with zero groups (e.g. 'ing' or '(?:.*)ing' with a non-capturing group) or more than two groups, without enabling two_groups_regexp.","commonSituations":"Writing a regex without parentheses around the captured stem, using (?:...) thinking it captures, or building the regex dynamically and miscounting groups.","solutions":["Wrap the part of the regex you want kept in exactly one capturing group: e.g. '(.*)ing'.","If you truly need two capture groups, add the two_groups_regexp arg to the filter.","Test the regex offline (Pattern.compile(...).matcher(...).groupCount()) before putting it in the rule."],"exampleFix":"<!-- before -->\n<filter class=\"...PartialPosTagFilter\" args=\"no:1 regexp:.*ing postag_regexp:VBZ\"/>\n<!-- after -->\n<filter class=\"...PartialPosTagFilter\" args=\"no:1 regexp:(.*)ing postag_regexp:VBZ\"/>","handlingStrategy":"validation","validationCode":"int groups = java.util.regex.Pattern.compile(regexp).matcher(\"\").pattern().matcher(\"\").groupCount(); // count via compiled pattern\nint groupCount = java.util.regex.Pattern.compile(regexp).matcher(\"\").groupCount() >= 0\n    ? java.util.regex.Pattern.compile(\"(x)?\").groupCount() // placeholder\n    : 0;\n// simpler check:\njava.util.regex.Pattern p = java.util.regex.Pattern.compile(regexp);\nif (p.matcher(\"\").groupCount() != 1) throw new IllegalArgumentException(\"regexp needs exactly 1 capturing group\");","typeGuard":null,"tryCatchPattern":"try {\n  return filter.acceptRuleMatch(match, args, pos, tokens, tokenPositions);\n} catch (RuntimeException e) {\n  throw new RuleFormatException(\"Bad PartialPosTagFilter regexp: \" + e.getMessage(), e);\n}","preventionTips":["Always parenthesize the captured stem: (.*)","Use (?:...) for non-capturing parts to keep group count at 1","Test groupCount() in a scratch program before adding the rule"],"tags":["java","languagetool","regex","capture-groups"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}