diff --git a/javalib/src/main/scala/java/util/regex/Matcher.scala b/javalib/src/main/scala/java/util/regex/Matcher.scala index 53f4c3a45d..7bfe84fbd2 100644 --- a/javalib/src/main/scala/java/util/regex/Matcher.scala +++ b/javalib/src/main/scala/java/util/regex/Matcher.scala @@ -24,6 +24,9 @@ final class Matcher private[regex] ( private var lastMatchIsValid = false private var canStillFind = true + // Group count + private var lastGroupCount: Option[Int] = None + // Append state (updated by replacement methods) private var appendPos: Int = 0 @@ -160,6 +163,7 @@ final class Matcher private[regex] ( regexp = pattern.newJSRegExp() regexp.lastIndex = prevLastIndex lastMatch = null + lastGroupCount = None startOfGroupCache = None this } @@ -172,7 +176,21 @@ final class Matcher private[regex] ( lastMatch } - def groupCount(): Int = ensureLastMatch.length-1 + def groupCount(): Int = { + if (lastMatch != null) { + lastMatch.length-1 + } else { + lastGroupCount match { + case Some(n) => n + + case None => + val groupCountRegex = new js.RegExp("|" + pattern0.jsPattern) + val newGroupCount = groupCountRegex.exec("").length-1 + lastGroupCount = Some(newGroupCount) + newGroupCount + } + } + } def start(): Int = ensureLastMatch.index def end(): Int = start() + group().length @@ -198,7 +216,7 @@ final class Matcher private[regex] ( // Seal the state - def toMatchResult(): MatchResult = new SealedResult(inputstr, lastMatch, pattern()) + def toMatchResult(): MatchResult = new SealedResult(inputstr, lastMatch, pattern(), groupCount()) // Other query state methods @@ -249,10 +267,11 @@ object Matcher { } private final class SealedResult(inputstr: String, - lastMatch: js.RegExp.ExecResult, pattern: Pattern) + lastMatch: js.RegExp.ExecResult, pattern: Pattern, + lastGroupCount: Int) extends MatchResult { - def groupCount(): Int = ensureLastMatch.length-1 + def groupCount(): Int = lastGroupCount def start(): Int = ensureLastMatch.index def end(): Int = start() + group().length diff --git a/test-suite/shared/src/test/scala/org/scalajs/testsuite/javalib/util/regex/RegexMatcherTest.scala b/test-suite/shared/src/test/scala/org/scalajs/testsuite/javalib/util/regex/RegexMatcherTest.scala index fb01d3beb2..4e487b41eb 100644 --- a/test-suite/shared/src/test/scala/org/scalajs/testsuite/javalib/util/regex/RegexMatcherTest.scala +++ b/test-suite/shared/src/test/scala/org/scalajs/testsuite/javalib/util/regex/RegexMatcherTest.scala @@ -102,6 +102,7 @@ class RegexMatcherTest { def parseExpect(regex: String, str: String, pos: (Int, Int)*): Unit = { val matcher = Pattern.compile(regex).matcher(str) + assertEquals(pos.length - 1, matcher.groupCount) assertTrue(matcher.find()) assertEquals(pos.length - 1, matcher.groupCount) var i = 0 @@ -159,6 +160,8 @@ class RegexMatcherTest { } def checkGroups(matcher: Matcher, startEndMatch: (Int, Int, String)*): Unit = { + assertEquals(startEndMatch.size - 1, matcher.groupCount) + assertTrue(matcher.find()) assertEquals(startEndMatch(0)._1, matcher.start) @@ -233,6 +236,13 @@ class RegexMatcherTest { assertTrue(matcher1.matches()) matcher1.usePattern(patternNoDots) assertFalse(matcher1.matches()) + + val patternWithOneGroup = Pattern.compile("ab(cd)efg") + val patternWithTwoGroups = Pattern.compile("ab(cd)(ef)g") + val matcher2 = patternWithOneGroup.matcher("Scala.js") + assertEquals(1, matcher2.groupCount()) + matcher2.usePattern(patternWithTwoGroups) + assertEquals(2, matcher2.groupCount()) } @Test def lookingAt(): Unit = {