diff --git a/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt b/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt index c5b811697f2..d33c667ea6d 100644 --- a/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt +++ b/libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt @@ -123,7 +123,7 @@ public class Regex internal constructor(private val nativePattern: Pattern) { * @param startIndex An index to start search with, by default 0. Must be not less than zero and not greater than `input.length()` * @return An instance of [MatchResult] if match was found or `null` otherwise. */ - public fun match(input: CharSequence, startIndex: Int = 0): MatchResult? = nativePattern.matcher(input).findNext(startIndex) + public fun match(input: CharSequence, startIndex: Int = 0): MatchResult? = nativePattern.matcher(input).findNext(startIndex, input) /** * Returns a sequence of all occurrences of a regular expression within the [input] string, beginning at the specified [startIndex]. @@ -216,38 +216,39 @@ public fun Pattern.toRegex(): Regex = Regex(this) // implementation -private fun Matcher.findNext(from: Int): MatchResult? { - if (!find(from)) - return null +private fun Matcher.findNext(from: Int, input: CharSequence): MatchResult? { + return if (!find(from)) null else MatcherMatchResult(this, input) +} - val matchResult = this.toMatchResult() +private class MatcherMatchResult(private val matcher: Matcher, private val input: CharSequence) : MatchResult { + private val matchResult = matcher.toMatchResult() + override val range: IntRange + get() = matchResult.range() + override val value: String + get() = matchResult.group() - return object: MatchResult { - override val range: IntRange - get() = matchResult.range() - override val value: String - get() = matchResult.group() + override val groups: MatchGroupCollection = object : MatchGroupCollection { + override fun size(): Int = matchResult.groupCount() + 1 + override fun isEmpty(): Boolean = false + override fun contains(o: Any?): Boolean = o is MatchGroup? && this.any({ it == o }) + override fun containsAll(c: Collection): Boolean = c.all({contains(it)}) - override val groups: MatchGroupCollection = object : MatchGroupCollection { - override fun size(): Int = matchResult.groupCount() + 1 - override fun isEmpty(): Boolean = false - override fun contains(o: Any?): Boolean = o is MatchGroup? && this.any({ it == o }) - override fun containsAll(c: Collection): Boolean = c.all({contains(it)}) - - override fun iterator(): Iterator = indices.asSequence().map { this[it] }.iterator() - override fun get(index: Int): MatchGroup? { - val range = matchResult.range(index) - return if (range.start >= 0) - MatchGroup(matchResult.group(index), range) - else - null - } + override fun iterator(): Iterator = indices.asSequence().map { this[it] }.iterator() + override fun get(index: Int): MatchGroup? { + val range = matchResult.range(index) + return if (range.start >= 0) + MatchGroup(matchResult.group(index), range) + else + null } + } - - override fun next(): MatchResult? = this@findNext.findNext(matchResult.end() + if (matchResult.end() == matchResult.start()) 1 else 0) + override fun next(): MatchResult? { + val nextIndex = matchResult.end() + if (matchResult.end() == matchResult.start()) 1 else 0 + return if (nextIndex <= input.length()) matcher.findNext(nextIndex, input) else null } } + private fun java.util.regex.MatchResult.range(): IntRange = start()..end()-1 private fun java.util.regex.MatchResult.range(groupIndex: Int): IntRange = start(groupIndex)..end(groupIndex)-1 diff --git a/libraries/stdlib/test/text/RegexTest.kt b/libraries/stdlib/test/text/RegexTest.kt index 076689dba37..5e74ab486ca 100644 --- a/libraries/stdlib/test/text/RegexTest.kt +++ b/libraries/stdlib/test/text/RegexTest.kt @@ -54,6 +54,15 @@ class RegexTest { assertEquals(listOf(0..2, 4..6, 8..10), matches.map { it.range }.toList()) } + test fun matchAllSequence() { + val input = "test" + val pattern = ".*".toRegex() + val matches = pattern.matchAll(input).toList() + assertEquals(input, matches[0].value) + assertEquals(input, matches.joinToString("") { it.value }) + assertEquals(2, matches.size()) + } + test fun matchGroups() { val input = "1a 2b 3c" val pattern = "(\\d)(\\w)".toRegex()