diff --git a/libraries/stdlib/jre8/src/kotlin/internal/JRE8PlatformImplementations.kt b/libraries/stdlib/jre8/src/kotlin/internal/JRE8PlatformImplementations.kt index bd14b152c0d..365a9149a26 100644 --- a/libraries/stdlib/jre8/src/kotlin/internal/JRE8PlatformImplementations.kt +++ b/libraries/stdlib/jre8/src/kotlin/internal/JRE8PlatformImplementations.kt @@ -1,5 +1,19 @@ package kotlin.internal +import java.util.regex.MatchResult +import java.util.regex.Matcher + @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "CANNOT_OVERRIDE_INVISIBLE_MEMBER") internal open class JRE8PlatformImplementations : JRE7PlatformImplementations() { + + override fun getMatchResultNamedGroup(matchResult: MatchResult, name: String): MatchGroup? { + val matcher = matchResult as? Matcher ?: throw UnsupportedOperationException("Retrieving groups by name is not supported on this platform.") + + val range = matcher.start(name)..matcher.end(name)-1 + return if (range.start >= 0) + MatchGroup(matcher.group(name), range) + else + null + } + } diff --git a/libraries/stdlib/jre8/src/kotlin/text/RegexExtensions.kt b/libraries/stdlib/jre8/src/kotlin/text/RegexExtensions.kt new file mode 100644 index 00000000000..78c8367050d --- /dev/null +++ b/libraries/stdlib/jre8/src/kotlin/text/RegexExtensions.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("RegexExtensionsJRE8Kt") +package kotlin.text + +/** + * Returns a named group with the specified [name]. + * + * @return An instance of [MatchGroup] if the group with the specified [name] was matched or `null` otherwise. + * @throws [UnsupportedOperationException] if getting named groups isn't supported on the current platform. + */ +public operator fun MatchGroupCollection.get(name: String): MatchGroup? { + val namedGroups = this as? MatchNamedGroupCollection ?: + throw UnsupportedOperationException("Retrieving groups by name is not supported on this platform.") + + return namedGroups[name] +} diff --git a/libraries/stdlib/jre8/test/text/RegexTest.kt b/libraries/stdlib/jre8/test/text/RegexTest.kt new file mode 100644 index 00000000000..55c10468feb --- /dev/null +++ b/libraries/stdlib/jre8/test/text/RegexTest.kt @@ -0,0 +1,27 @@ +package kotlin.text.test + +import org.junit.Test +import kotlin.test.* + + +class RegexTest { + @Test fun namedGroups() { + val input = "1a 2b 3c" + val regex = "(?\\d)(?\\w)".toRegex() + + val matches = regex.findAll(input).toList() + assertTrue(matches.all { it.groups.size == 3 }) + val m1 = matches[0] + + assertEquals("1", m1.groups["num"]?.value) + assertEquals(0..0, m1.groups["num"]?.range) + assertEquals("a", m1.groups["liter"]?.value) + assertEquals(1..1, m1.groups["liter"]?.range) + + val m2 = matches[1] + assertEquals("2", m2.groups["num"]?.value) + assertEquals(3..3, m2.groups["num"]?.range) + assertEquals("b", m2.groups["liter"]?.value) + assertEquals(4..4, m2.groups["liter"]?.range) + } +} \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/internal/PlatformImplementations.kt b/libraries/stdlib/src/kotlin/internal/PlatformImplementations.kt index 1c7cd7158c1..158eb814e92 100644 --- a/libraries/stdlib/src/kotlin/internal/PlatformImplementations.kt +++ b/libraries/stdlib/src/kotlin/internal/PlatformImplementations.kt @@ -2,6 +2,7 @@ package kotlin.internal import java.io.Closeable +import java.util.regex.MatchResult internal open class PlatformImplementations { @@ -16,6 +17,10 @@ internal open class PlatformImplementations { } } + public open fun getMatchResultNamedGroup(matchResult: MatchResult, name: String): MatchGroup? { + throw UnsupportedOperationException("Retrieving groups by name is not supported on this platform.") + } + companion object { @JvmField @InlineExposed @@ -52,5 +57,7 @@ internal open class PlatformImplementations { } } + + } diff --git a/libraries/stdlib/src/kotlin/text/regex/MatchResult.kt b/libraries/stdlib/src/kotlin/text/regex/MatchResult.kt index aa8d97fc6fe..e406ce36537 100644 --- a/libraries/stdlib/src/kotlin/text/regex/MatchResult.kt +++ b/libraries/stdlib/src/kotlin/text/regex/MatchResult.kt @@ -36,8 +36,17 @@ public interface MatchGroupCollection : Collection { * corresponds to the entire match. */ public operator fun get(index: Int): MatchGroup? +} - // TODO: Provide get(name: String) on JVM 7+ +/** + * Extends [MatchGroupCollection] by introducing a way to get matched groups by name, when regex supports it. + */ +public interface MatchNamedGroupCollection : MatchGroupCollection { + /** + * Returns a named group with the specified [name]. + * @return An instance of [MatchGroup] if the group with the specified [name] was matched or `null` otherwise. + */ + public operator fun get(name: String): MatchGroup? } /** diff --git a/libraries/stdlib/src/kotlin/text/regex/Regex.kt b/libraries/stdlib/src/kotlin/text/regex/Regex.kt index 7bacfb78ef2..cc8f7031c83 100644 --- a/libraries/stdlib/src/kotlin/text/regex/Regex.kt +++ b/libraries/stdlib/src/kotlin/text/regex/Regex.kt @@ -19,6 +19,7 @@ package kotlin.text import java.util.* import java.util.regex.Matcher import java.util.regex.Pattern +import kotlin.internal.DefaultPlatformImplementations private interface FlagEnum { public val value: Int @@ -231,7 +232,7 @@ private class MatcherMatchResult(private val matcher: Matcher, private val input override val value: String get() = matchResult.group() - override val groups: MatchGroupCollection = object : MatchGroupCollection { + override val groups: MatchGroupCollection = object : MatchNamedGroupCollection { override val size: Int get() = matchResult.groupCount() + 1 override fun isEmpty(): Boolean = false override fun contains(element: MatchGroup?): Boolean = this.any { it == element } @@ -245,6 +246,9 @@ private class MatcherMatchResult(private val matcher: Matcher, private val input else null } + override fun get(name: String): MatchGroup? { + return DefaultPlatformImplementations.INSTANCE.getMatchResultNamedGroup(matchResult, name) + } } private var groupValues_: List? = null