Skip to content

Commit

Permalink
Stop matching after the end of the input sequence was reached.
Browse files Browse the repository at this point in the history
#KT-8763 Fixed
  • Loading branch information
ilya-g authored and Sergey Mashkov committed Aug 11, 2015
1 parent c745779 commit 15d6949
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 29 deletions.
59 changes: 30 additions & 29 deletions libraries/stdlib/src/kotlin/text/regex/RegexJVM.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down Expand Up @@ -216,38 +216,39 @@ public fun Pattern.toRegex(): Regex = Regex(this)

// implementation

private fun Matcher.findNext(from: Int): MatchResult? {
if (!find(from))
return null

val matchResult = this.toMatchResult()

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<Any?>): Boolean = c.all({contains(it)})

override fun iterator(): Iterator<MatchGroup?> = 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
}
}
private fun Matcher.findNext(from: Int, input: CharSequence): MatchResult? {
return if (!find(from)) null else MatcherMatchResult(this, input)
}

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()

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<Any?>): Boolean = c.all({contains(it)})

override fun iterator(): Iterator<MatchGroup?> = 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
9 changes: 9 additions & 0 deletions libraries/stdlib/test/text/RegexTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 15d6949

Please sign in to comment.