[JS] Support named capture groups in Regex #KT-51775

This commit is contained in:
Abduqodiri Qurbonzoda
2021-09-28 02:20:22 +03:00
committed by Space
parent cf79752c14
commit c3f5d03b36
9 changed files with 217 additions and 33 deletions
+80 -1
View File
@@ -155,6 +155,68 @@ class RegexTest {
}
}
@Test fun matchNamedGroups() {
val regex = "\\b(?<city>[A-Za-z\\s]+),\\s(?<state>[A-Z]{2}):\\s(?<areaCode>[0-9]{3})\\b".toRegex()
val input = "Coordinates: Austin, TX: 123"
regex.find(input)!!.let { match ->
assertEquals(listOf("Austin, TX: 123", "Austin", "TX", "123"), match.groupValues)
if (supportsNamedCapturingGroup) {
val namedGroups = match.groups as MatchNamedGroupCollection
assertEquals(4, namedGroups.size)
assertEquals("Austin", namedGroups["city"]?.value)
assertEquals("TX", namedGroups["state"]?.value)
assertEquals("123", namedGroups["areaCode"]?.value)
}
}
}
@Test fun matchOptionalNamedGroup() {
if (!supportsNamedCapturingGroup) return
"(?<hi>hi)|(?<bye>bye)".toRegex(RegexOption.IGNORE_CASE).let { regex ->
val hiMatch = regex.find("Hi!")!!
val hiGroups = hiMatch.groups as MatchNamedGroupCollection
assertEquals(3, hiGroups.size)
assertEquals("Hi", hiGroups["hi"]?.value)
assertEquals(null, hiGroups["bye"])
assertFailsWith<IllegalArgumentException> { hiGroups["hello"] }
val byeMatch = regex.find("bye...")!!
val byeGroups = byeMatch.groups as MatchNamedGroupCollection
assertEquals(3, byeGroups.size)
assertEquals(null, byeGroups["hi"])
assertEquals("bye", byeGroups["bye"]?.value)
assertFailsWith<IllegalArgumentException> { byeGroups["goodbye"] }
}
"(?<hi>hi)|bye".toRegex(RegexOption.IGNORE_CASE).let { regex ->
val hiMatch = regex.find("Hi!")!!
val hiGroups = hiMatch.groups as MatchNamedGroupCollection
assertEquals(2, hiGroups.size)
assertEquals("Hi", hiGroups["hi"]?.value)
assertFailsWith<IllegalArgumentException> { hiGroups["bye"] }
// Named group collection consisting of a single 'null' group value
val byeMatch = regex.find("bye...")!!
val byeGroups = byeMatch.groups as MatchNamedGroupCollection
assertEquals(2, byeGroups.size)
assertEquals(null, byeGroups["hi"])
assertFailsWith<IllegalArgumentException> { byeGroups["bye"] }
}
}
@Test fun matchWithBackReference() {
val regex = "(?<title>\\w+), yes \\k<title>".toRegex()
val match = regex.find("Do you copy? Sir, yes Sir!")!!
assertEquals("Sir, yes Sir", match.value)
assertEquals("Sir", (match.groups as MatchNamedGroupCollection)["title"]?.value)
assertNull(regex.find("Do you copy? Sir, yes I do!"))
}
@Test fun matchMultiline() {
val regex = "^[a-z]*$".toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE))
val matchedValues = regex.findAll("test\n\nLine").map { it.value }.toList()
@@ -298,7 +360,7 @@ class RegexTest {
"123-456".let { input ->
assertEquals("(123-456)", pattern.replace(input, "($0)"))
assertEquals("123+456", pattern.replace(input, "$1+$2"))
// take largest legal group number reference
// take the largest legal group number reference
assertEquals("1230+456", pattern.replace(input, "$10+$2"))
assertEquals("123+456", pattern.replace(input, "$01+$2"))
// js refers to named capturing groups with "$<name>" syntax
@@ -308,6 +370,11 @@ class RegexTest {
// missing trailing '}'
assertFailsWith<IllegalArgumentException>("\${first+\${second}") { pattern.replace(input, "\${first+\${second}") }
assertFailsWith<IllegalArgumentException>("\${first}+\${second") { pattern.replace(input, "\${first}+\${second") }
// non-existent group name
assertFailsWith<IllegalArgumentException>("\${first}+\${second}+\$third") {
pattern.replace(input, "\${first}+\${second}+\$third")
}
}
"123-456-789-012".let { input ->
@@ -317,6 +384,18 @@ class RegexTest {
}
}
@Test fun replaceWithNamedOptionalGroups() {
if (!supportsNamedCapturingGroup) return
val regex = "(?<hi>hi)|(?<bye>bye)".toRegex(RegexOption.IGNORE_CASE)
assertEquals("[Hi, ]gh wall", regex.replace("High wall", "[$1, $2]"))
assertEquals("[Hi, ]gh wall", regex.replace("High wall", "[\${hi}, \${bye}]"))
assertEquals("Good[, bye], Mr. Holmes", regex.replace("Goodbye, Mr. Holmes", "[$1, $2]"))
assertEquals("Good[, bye], Mr. Holmes", regex.replace("Goodbye, Mr. Holmes", "[\${hi}, \${bye}]"))
}
@Test fun replaceEvaluator() {
val input = "/12/456/7890/"
val pattern = "\\d+".toRegex()