Regex: MatchResult.groupValues do not exclude zeroth group, use the same indices as in groups collection.
Provide destructured property for destructured assignment.
This commit is contained in:
@@ -216,8 +216,8 @@ private fun RegExp.findNext(input: String, from: Int): MatchResult? {
|
|||||||
get() {
|
get() {
|
||||||
if (groupValues_ == null) {
|
if (groupValues_ == null) {
|
||||||
groupValues_ = object : java.util.AbstractList<String>() {
|
groupValues_ = object : java.util.AbstractList<String>() {
|
||||||
override val size: Int get() = match.size - 1
|
override val size: Int get() = match.size
|
||||||
override fun get(index: Int): String = match[index + 1] ?: ""
|
override fun get(index: Int): String = match[index] ?: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return groupValues_!!
|
return groupValues_!!
|
||||||
@@ -225,4 +225,19 @@ private fun RegExp.findNext(input: String, from: Int): MatchResult? {
|
|||||||
|
|
||||||
override fun next(): MatchResult? = this@findNext.findNext(input, if (range.isEmpty()) range.start + 1 else range.end + 1)
|
override fun next(): MatchResult? = this@findNext.findNext(input, if (range.isEmpty()) range.start + 1 else range.end + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move into MatchResult after KT-4124 is implemented
|
||||||
|
public class Destructured internal constructor(public val match: MatchResult) {
|
||||||
|
public operator inline fun component1(): String = match.groupValues[1]
|
||||||
|
public operator inline fun component2(): String = match.groupValues[2]
|
||||||
|
public operator inline fun component3(): String = match.groupValues[3]
|
||||||
|
public operator inline fun component4(): String = match.groupValues[4]
|
||||||
|
public operator inline fun component5(): String = match.groupValues[5]
|
||||||
|
public operator inline fun component6(): String = match.groupValues[6]
|
||||||
|
public operator inline fun component7(): String = match.groupValues[7]
|
||||||
|
public operator inline fun component8(): String = match.groupValues[8]
|
||||||
|
public operator inline fun component9(): String = match.groupValues[9]
|
||||||
|
public operator inline fun component10(): String = match.groupValues[10]
|
||||||
|
public fun toList(): List<String> = match.groupValues.drop(1)
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,19 +56,58 @@ public interface MatchResult {
|
|||||||
*/
|
*/
|
||||||
public val groups: MatchGroupCollection
|
public val groups: MatchGroupCollection
|
||||||
/**
|
/**
|
||||||
* A list of matched indexed group values except zeroth group corresponding to the entire match.
|
* A list of matched indexed group values.
|
||||||
*
|
*
|
||||||
* Unlike [groups] collection this list contains exactly `groupCount` items where `groupCount` is the count of groups in the regular expression.
|
* This list has size of `groupCount + 1` where `groupCount` is the count of groups in the regular expression.
|
||||||
* Groups are are indexed from *zero* to the `groupCount - 1`.
|
* Groups are indexed from 1 to `groupCount` and group with the index 0 corresponds to the entire match.
|
||||||
*
|
*
|
||||||
* If the group in the regular expression is optional and there was not match captured by that group,
|
* If the group in the regular expression is optional and there were no match captured by that group,
|
||||||
* corresponding item in [groupValues] would be an empty string.
|
* corresponding item in [groupValues] is an empty string.
|
||||||
*/
|
*/
|
||||||
public val groupValues: List<String>
|
public val groupValues: List<String>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of [MatchResult.Destructured] wrapper providing components for destructuring assignment of group values.
|
||||||
|
*
|
||||||
|
* component1 corresponds to the value of the first group, component2 — of the second, and so on.
|
||||||
|
*
|
||||||
|
* @sample:
|
||||||
|
* ```
|
||||||
|
* val (name, phone) = Regex("(\\w+) (\\d+)").match(inputString)!!.destructured
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
public val destructured: Destructured get() = Destructured(this)
|
||||||
|
|
||||||
/** Returns a new [MatchResult] with the results for the next match, starting at the position
|
/** Returns a new [MatchResult] with the results for the next match, starting at the position
|
||||||
* at which the last match ended (at the character after the last matched character).
|
* at which the last match ended (at the character after the last matched character).
|
||||||
*/
|
*/
|
||||||
public fun next(): MatchResult?
|
public fun next(): MatchResult?
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides components for destructuring assignment of group values.
|
||||||
|
*
|
||||||
|
* [component1] corresponds to the value of the first group, [component2] — of the second, and so on.
|
||||||
|
*
|
||||||
|
* If the group in the regular expression is optional and there were no match captured by that group,
|
||||||
|
* corresponding component value is an empty string.
|
||||||
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
@kotlin.jvm.JvmVersion
|
||||||
|
public class Destructured internal constructor(public val match: MatchResult) {
|
||||||
|
public operator inline fun component1(): String = match.groupValues[1]
|
||||||
|
public operator inline fun component2(): String = match.groupValues[2]
|
||||||
|
public operator inline fun component3(): String = match.groupValues[3]
|
||||||
|
public operator inline fun component4(): String = match.groupValues[4]
|
||||||
|
public operator inline fun component5(): String = match.groupValues[5]
|
||||||
|
public operator inline fun component6(): String = match.groupValues[6]
|
||||||
|
public operator inline fun component7(): String = match.groupValues[7]
|
||||||
|
public operator inline fun component8(): String = match.groupValues[8]
|
||||||
|
public operator inline fun component9(): String = match.groupValues[9]
|
||||||
|
public operator inline fun component10(): String = match.groupValues[10]
|
||||||
|
/**
|
||||||
|
* Returns destructured group values as a list of strings.
|
||||||
|
* First value in the returned list corresponds to the value of the first group, and so on.
|
||||||
|
*/
|
||||||
|
public fun toList(): List<String> = match.groupValues.subList(1, match.groupValues.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -263,8 +263,8 @@ private class MatcherMatchResult(private val matcher: Matcher, private val input
|
|||||||
get() {
|
get() {
|
||||||
if (groupValues_ == null) {
|
if (groupValues_ == null) {
|
||||||
groupValues_ = object : AbstractList<String>() {
|
groupValues_ = object : AbstractList<String>() {
|
||||||
override val size: Int get() = matchResult.groupCount()
|
override val size: Int get() = matchResult.groupCount() + 1
|
||||||
override fun get(index: Int): String = matchResult.group(index + 1) ?: ""
|
override fun get(index: Int): String = matchResult.group(index) ?: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return groupValues_!!
|
return groupValues_!!
|
||||||
|
|||||||
@@ -69,36 +69,62 @@ class RegexTest {
|
|||||||
|
|
||||||
val matches = pattern.findAll(input).toList()
|
val matches = pattern.findAll(input).toList()
|
||||||
assertTrue(matches.all { it.groups.size == 3 })
|
assertTrue(matches.all { it.groups.size == 3 })
|
||||||
val m1 = matches[0]
|
|
||||||
assertEquals("1a", m1.groups[0]?.value)
|
|
||||||
assertEquals("1", m1.groups[1]?.value)
|
|
||||||
assertEquals("a", m1.groups[2]?.value)
|
|
||||||
|
|
||||||
assertEquals(listOf("1", "a"), m1.groupValues)
|
matches[0].let { m ->
|
||||||
|
assertEquals("1a", m.groups[0]?.value)
|
||||||
|
assertEquals("1", m.groups[1]?.value)
|
||||||
|
assertEquals("a", m.groups[2]?.value)
|
||||||
|
|
||||||
val m2 = matches[1]
|
assertEquals(listOf("1a", "1", "a"), m.groupValues)
|
||||||
assertEquals("2", m2.groups[1]?.value)
|
|
||||||
assertEquals("b", m2.groups[2]?.value)
|
|
||||||
|
|
||||||
assertEquals(listOf("2", "b"), m2.groupValues)
|
val (g1, g2) = m.destructured
|
||||||
|
assertEquals("1", g1)
|
||||||
|
assertEquals("a", g2)
|
||||||
|
assertEquals(listOf("1", "a"), m.destructured.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
matches[1].let { m ->
|
||||||
|
assertEquals("2b", m.groups[0]?.value)
|
||||||
|
assertEquals("2", m.groups[1]?.value)
|
||||||
|
assertEquals("b", m.groups[2]?.value)
|
||||||
|
|
||||||
|
assertEquals(listOf("2b", "2", "b"), m.groupValues)
|
||||||
|
|
||||||
|
val (g1, g2) = m.destructured
|
||||||
|
assertEquals("2", g1)
|
||||||
|
assertEquals("b", g2)
|
||||||
|
assertEquals(listOf("2", "b"), m.destructured.toList())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@test fun matchOptionalGroup() {
|
@test fun matchOptionalGroup() {
|
||||||
val pattern = "(hi)|(bye)".toRegex(RegexOption.IGNORE_CASE)
|
val pattern = "(hi)|(bye)".toRegex(RegexOption.IGNORE_CASE)
|
||||||
|
|
||||||
val m1 = pattern.find("Hi!")!!
|
pattern.find("Hi!")!!.let { m ->
|
||||||
assertEquals(3, m1.groups.size)
|
assertEquals(3, m.groups.size)
|
||||||
assertEquals("Hi", m1.groups[1]?.value)
|
assertEquals("Hi", m.groups[1]?.value)
|
||||||
assertEquals(null, m1.groups[2])
|
assertEquals(null, m.groups[2])
|
||||||
|
|
||||||
assertEquals(listOf("Hi", ""), m1.groupValues)
|
assertEquals(listOf("Hi", "Hi", ""), m.groupValues)
|
||||||
|
|
||||||
val m2 = pattern.find("bye...")!!
|
val (g1, g2) = m.destructured
|
||||||
assertEquals(3, m2.groups.size)
|
assertEquals("Hi", g1)
|
||||||
assertEquals(null, m2.groups[1])
|
assertEquals("", g2)
|
||||||
assertEquals("bye", m2.groups[2]?.value)
|
assertEquals(listOf("Hi", ""), m.destructured.toList())
|
||||||
|
}
|
||||||
|
|
||||||
assertEquals(listOf("", "bye"), m2.groupValues)
|
pattern.find("bye...")!!.let { m ->
|
||||||
|
assertEquals(3, m.groups.size)
|
||||||
|
assertEquals(null, m.groups[1])
|
||||||
|
assertEquals("bye", m.groups[2]?.value)
|
||||||
|
|
||||||
|
assertEquals(listOf("bye", "", "bye"), m.groupValues)
|
||||||
|
|
||||||
|
val (g1, g2) = m.destructured
|
||||||
|
assertEquals("", g1)
|
||||||
|
assertEquals("bye", g2)
|
||||||
|
assertEquals(listOf("", "bye"), m.destructured.toList())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@test fun matchMultiline() {
|
@test fun matchMultiline() {
|
||||||
|
|||||||
Reference in New Issue
Block a user