Find correct next match after matchAt and matchEntire KT-47676
This commit is contained in:
committed by
teamcityserver
parent
28a0698463
commit
455fee29e4
@@ -58,6 +58,15 @@ public actual class Regex actual constructor(pattern: String, options: Set<Regex
|
|||||||
private fun initStickyPattern(): RegExp =
|
private fun initStickyPattern(): RegExp =
|
||||||
nativeStickyPattern ?: RegExp(pattern, options.toFlags("yu")).also { nativeStickyPattern = it }
|
nativeStickyPattern ?: RegExp(pattern, options.toFlags("yu")).also { nativeStickyPattern = it }
|
||||||
|
|
||||||
|
private var nativeMatchesEntirePattern: RegExp? = null
|
||||||
|
private fun initMatchesEntirePattern(): RegExp =
|
||||||
|
nativeMatchesEntirePattern ?: run {
|
||||||
|
if (pattern.startsWith('^') && pattern.endsWith('$'))
|
||||||
|
nativePattern
|
||||||
|
else
|
||||||
|
return RegExp("^${pattern.trimStart('^').trimEnd('$')}$", options.toFlags("gu"))
|
||||||
|
}.also { nativeMatchesEntirePattern = it }
|
||||||
|
|
||||||
|
|
||||||
/** Indicates whether the regular expression matches the entire [input]. */
|
/** Indicates whether the regular expression matches the entire [input]. */
|
||||||
public actual infix fun matches(input: CharSequence): Boolean {
|
public actual infix fun matches(input: CharSequence): Boolean {
|
||||||
@@ -96,7 +105,7 @@ public actual class Regex actual constructor(pattern: String, options: Set<Regex
|
|||||||
if (startIndex < 0 || startIndex > input.length) {
|
if (startIndex < 0 || startIndex > input.length) {
|
||||||
throw IndexOutOfBoundsException("Start index out of bounds: $startIndex, input length: ${input.length}")
|
throw IndexOutOfBoundsException("Start index out of bounds: $startIndex, input length: ${input.length}")
|
||||||
}
|
}
|
||||||
return nativePattern.findNext(input.toString(), startIndex)
|
return nativePattern.findNext(input.toString(), startIndex, nativePattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,12 +128,8 @@ public actual class Regex actual constructor(pattern: String, options: Set<Regex
|
|||||||
*
|
*
|
||||||
* @return An instance of [MatchResult] if the entire input matches or `null` otherwise.
|
* @return An instance of [MatchResult] if the entire input matches or `null` otherwise.
|
||||||
*/
|
*/
|
||||||
public actual fun matchEntire(input: CharSequence): MatchResult? {
|
public actual fun matchEntire(input: CharSequence): MatchResult? =
|
||||||
if (pattern.startsWith('^') && pattern.endsWith('$'))
|
initMatchesEntirePattern().findNext(input.toString(), 0, nativePattern)
|
||||||
return find(input)
|
|
||||||
else
|
|
||||||
return Regex("^${pattern.trimStart('^').trimEnd('$')}$", options).find(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SinceKotlin("1.5")
|
@SinceKotlin("1.5")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@@ -132,7 +137,7 @@ public actual class Regex actual constructor(pattern: String, options: Set<Regex
|
|||||||
if (index < 0 || index > input.length) {
|
if (index < 0 || index > input.length) {
|
||||||
throw IndexOutOfBoundsException("index out of bounds: $index, input length: ${input.length}")
|
throw IndexOutOfBoundsException("index out of bounds: $index, input length: ${input.length}")
|
||||||
}
|
}
|
||||||
return initStickyPattern().findNext(input.toString(), index)
|
return initStickyPattern().findNext(input.toString(), index, nativePattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -247,7 +252,7 @@ public fun Regex_1(pattern: String): Regex = Regex(pattern, emptySet())
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun RegExp.findNext(input: String, from: Int): MatchResult? {
|
private fun RegExp.findNext(input: String, from: Int, nextPattern: RegExp): MatchResult? {
|
||||||
this.lastIndex = from
|
this.lastIndex = from
|
||||||
val match = exec(input)
|
val match = exec(input)
|
||||||
if (match == null) return null
|
if (match == null) return null
|
||||||
@@ -278,6 +283,7 @@ private fun RegExp.findNext(input: String, from: Int): MatchResult? {
|
|||||||
return groupValues_!!
|
return groupValues_!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun next(): MatchResult? = this@findNext.findNext(input, if (range.isEmpty()) range.start + 1 else range.endInclusive + 1)
|
override fun next(): MatchResult? =
|
||||||
|
nextPattern.findNext(input, if (range.isEmpty()) range.start + 1 else range.endInclusive + 1, nextPattern)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ class RegexTest {
|
|||||||
assertEquals("3c", m.value)
|
assertEquals("3c", m.value)
|
||||||
assertEquals(3, m.groups.size)
|
assertEquals(3, m.groups.size)
|
||||||
assertEquals(listOf("3c", "3", "c"), m.groups.map { it!!.value })
|
assertEquals(listOf("3c", "3", "c"), m.groups.map { it!!.value })
|
||||||
|
assertNull(m.next())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +180,17 @@ class RegexTest {
|
|||||||
assertEquals("aaaabbbb", regex.matchEntire(input)!!.value)
|
assertEquals("aaaabbbb", regex.matchEntire(input)!!.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun matchEntireNext() {
|
||||||
|
val regex = ".*".toRegex()
|
||||||
|
val input = "abc"
|
||||||
|
val match = regex.matchEntire(input)!!
|
||||||
|
assertEquals(input, match.value)
|
||||||
|
val next = assertNotNull(match.next())
|
||||||
|
assertEquals("", next.value)
|
||||||
|
assertEquals(input.length until input.length, next.range)
|
||||||
|
assertNull(next.next())
|
||||||
|
}
|
||||||
|
|
||||||
@Test fun matchAt() {
|
@Test fun matchAt() {
|
||||||
val regex = Regex("[a-z][1-5]", RegexOption.IGNORE_CASE)
|
val regex = Regex("[a-z][1-5]", RegexOption.IGNORE_CASE)
|
||||||
val input = "...a4...B1"
|
val input = "...a4...B1"
|
||||||
@@ -196,6 +208,11 @@ class RegexTest {
|
|||||||
assertEquals(input.substring(match.range), match.value)
|
assertEquals(input.substring(match.range), match.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matches.zipWithNext { (_, m1), (_, m2) ->
|
||||||
|
assertEquals(m2.range, assertNotNull(m1.next()).range)
|
||||||
|
}
|
||||||
|
assertNull(matches.last().second.next())
|
||||||
|
|
||||||
for (index in listOf(-1, input.length + 1)) {
|
for (index in listOf(-1, input.length + 1)) {
|
||||||
assertFailsWith<IndexOutOfBoundsException> { regex.matchAt(input, index) }
|
assertFailsWith<IndexOutOfBoundsException> { regex.matchAt(input, index) }
|
||||||
assertFailsWith<IndexOutOfBoundsException> { regex.matchesAt(input, index) }
|
assertFailsWith<IndexOutOfBoundsException> { regex.matchesAt(input, index) }
|
||||||
|
|||||||
Reference in New Issue
Block a user