Regular Expressions in Kotlin with Examples: In Practice
\n\nRegular expressions (regex) are a powerful tool for working with strings. In Kotlin, they are implemented based on the Java classes Pattern and Matcher, but the language adds its own convenient extensions and syntactic sugar. In this article, we will break down how to use regular expressions in Kotlin with real examples: from simple search to replacement and string splitting.
Syntax Basics: Creation and Compilation
\n\nIn Kotlin, a regular expression can be created in two ways: via the Regex class or using a string with a pattern. The first method is preferable as it provides more methods.
// Method 1: via the Regex class\nval regex = Regex("\\\\d+") // one or more digits\n\n// Method 2: via a string (not recommended for complex expressions)\nval pattern = "\\\\d+".toRegex()\n\nNote the double escape slash: \\\\d — this is escaping for Java/Kotlin to get the \\d character in the string. For simplicity, Kotlin supports raw strings (triple quotes """), where escaping is not required:
val regex = Regex("""\\d+""") // raw string — backslashes do not need to be duplicated\n\nYou can also add flags, for example, RegexOption.IGNORE_CASE:
val regex = Regex("kotlin", RegexOption.IGNORE_CASE)\n\nSearching and Checking Matches
\n\nThe most common operations are to check if a string contains a substring matching a pattern, and to find all matches.
\n\nChecking for a Match: containsMatchIn
\n\nval text = "My number: 123-45-678"\nval digitRegex = Regex("""\\d+""")\n\nif (digitRegex.containsMatchIn(text)) {\n println("The text contains digits!")\n}\n\nFinding the First Match: find
\n\nval result = digitRegex.find(text)\nprintln(result?.value) // Output: 123\n\nFinding All Matches: findAll
\n\nval allMatches = digitRegex.findAll(text)\nallMatches.forEach { match ->\n println("Found: ${match.value}") // 123, 45, 678\n}\n\nThe findAll method returns a sequence of MatchResult objects. Each such object contains not only the match itself (.value), but also its position in the string (.range).
Working with Capture Groups
\n\nCapture groups are parts of the pattern enclosed in parentheses. They allow you to extract specific data fragments. For example, let's parse an email into a username and domain:
\n\nval email = "user@example.com"\nval emailRegex = Regex("""(.+)@(.+)""")\nval matchResult = emailRegex.find(email)\n\nif (matchResult != null) {\n val (username, domain) = matchResult.destructured\n println("Username: $username") // user\n println("Domain: $domain") // example.com\n}\n\nThe destructured construct conveniently splits groups into variables. If there are more groups, you can access them by index:
val fullMatch = matchResult.value // user@example.com\nval group1 = matchResult.groupValues[1] // user\nval group2 = matchResult.groupValues[2] // example.com\n\nNamed Groups (Kotlin 1.7+)
\n\nStarting from Kotlin 1.7, you can use named groups:
\n\nval namedRegex = Regex("""(?<name>\\w+)@(?<domain>\\w+\\.\\w+)""")\nval match = namedRegex.find("contact@kotlin.org")\nif (match != null) {\n println(match.groups["name"]?.value) // contact\n println(match.groups["domain"]?.value) // kotlin.org\n}\n\nReplacing Text with replace
\n\nThe replace method allows you to replace all matches with a new string. In the replacement pattern, you can reference capture groups wi