Каждый разработчик рано или поздно сталкивается с задачей: проверить, правильно ли введён email, вытащить из строки все цифры или разбить текст по заковыристому шаблону. Писать для этого длинные цепочки условий — плохой путь. Kotlin регулярные выражения дают короткое и мощное решение. В этом уроке я объясню, что такое Regex, как создавать шаблоны и применять их в реальных сценариях, даже если вы никогда не слышали о регулярках раньше.
Что такое регулярное выражение
Регулярное выражение — это строка-шаблон, которая описывает, какие последовательности символов мы хотим найти в тексте. Например, шаблон \d+ означает «одна или несколько цифр подряд». Передав его в Kotlin-класс Regex, вы можете найти все числа в предложении или проверить, соответствует ли строка формату телефона.
Главный плюс — универсальность. Один и тот же шаблон работает похожим образом в Kotlin, Java, Python, JavaScript и даже в базах данных. Поэтому разобравшись с регулярками однажды, вы сможете использовать их в любых проектах.
Как создать Regex в Kotlin
Самый частый способ — вызвать метод toRegex() на обычной строке. Kotlin также позволяет создать объект через конструктор Regex() и при необходимости задать флаги, которые меняют поведение шаблона.
val pattern = "\\d+".toRegex() // через строку
val pattern2 = Regex("\\d+") // через конструктор
val pattern3 = Regex("\\d+", RegexOption.IGNORE_CASE) // с флагом
Обратите внимание: в строке Kotlin обратный слеш нужно экранировать, поэтому вместо одинарного \d пишем \\d. Если вы используете raw-строку (тройные кавычки), экранирование не требуется: """\d+""".toRegex().
Если нужно искать текст, в котором есть спецсимволы регулярных выражений (например, точку или звёздочку), применяйте метод fromLiteral(). Он превращает строку в шаблон, который ищет точное совпадение.
val literal = Regex.fromLiteral("hello.world") // найдёт именно hello.world, а не h-любой символ
Самые нужные методы Regex
Таблица ниже содержит основные методы класса Regex. Это ваш шпаргалка для повседневной работы с текстом.
| Метод | Что делает | Пример использования |
|---|---|---|
| containsMatchIn(input) | Проверяет, есть ли в строке хотя бы одно совпадение | "abc".containsMatchIn("123abc456") // true |
| matches(input) | Проверяет, соответствует ли вся строка шаблону целиком | "\\d+".matches("123") // true |
| find(input) | Находит первое совпадение, возвращает MatchResult? | "\\d+".find("abc123def")?.value // "123" |
| findAll(input) | Находит все совпадения, возвращает Sequence<MatchResult> | "\\d+".findAll("a1b22c333").map { it.value }.toList() // ["1","22","333"] |
| replace(input, replacement) | Заменяет все совпадения на строку-заменитель | "\\s+".replace("a b c", " ") // "a b c" |
| split(input) | Разрезает строку по местам совпадений, возвращает список | ",".toRegex().split("a,b,c") // ["a","b","c"] |
Поиск и проверка совпадений
Начнём с простого: проверка строки на соответствие формату. Допустим, нужно узнать, является ли введённый текст четырёхзначным числом. Используем якоря ^ (начало строки) и $ (конец строки), чтобы совпадение шло по всей длине, а не где-то внутри.
val pinPattern = "^\\d{4}$".toRegex()
println(pinPattern.matches("1234")) // true
println(pinPattern.matches("12345")) // false
Если нужно просто узнать, есть ли слово в тексте, подойдёт containsMatchIn. Это самый быстрый способ проверки.
val word = "kotlin".toRegex(RegexOption.IGNORE_CASE)
println(word.containsMatchIn("Я изучаю Kotlin")) // true
Извлечение данных из текста
Самая частая задача — вытащить из строки все цифры, email-адреса или номера телефонов. Комбинация findAll и лямбды делает это в одну цепочку. Никаких циклов не требуется.
val text = "Контакты: +7(999)123-45-67, +7(495)000-11-22"
val phoneRegex = "\\+7\\(\\d{3}\\)\\d{3}-\\d{2}-\\d{2}".toRegex()
val phones = phoneRegex.findAll(text).map { it.value }.toList()
// ["+7(999)123-45-67", "+7(495)000-11-22"]
Если достаточно только первого совпадения, используйте find. Он возвращает объект MatchResult, у которого есть удобные свойства: value (найденная подстрока), range (диапазон индексов), groupValues (захваченные группы).
val match = phoneRegex.find(text)
println(match?.value) // +7(999)123-45-67
println(match?.range) // 10..25
Группы: захват частей совпадения
Группы — это самая мощная фича регулярных выражений. Они позволяют не просто найти шаблон, но и разобрать его на смысловые куски. Всё, что заключено в круглые скобки в шаблоне, становится группой. Доступ к содержимому групп идёт через groupValues, где нулевой элемент — полное совпадение, а следующие — содержимое скобок по порядку.
val datePattern = "(\\d{2})/(\\d{2})/(\\d{4})".toRegex()
val dateText = "Сегодня 09/05/2026"
val dateMatch = datePattern.find(dateText)
if (dateMatch != null) {
val day = dateMatch.groupValues[1] // "09"
val month = dateMatch.groupValues[2] // "05"
val year = dateMatch.groupValues[3] // "2026"
println("День: $day, Месяц: $month, Год: $year")
}
Именованные группы тоже поддерживаются: используйте синтаксис (?<name>...), а для доступа — свойство groups["name"]?.value. Это удобно для сложных шаблонов, где сложно запомнить порядок скобок.
Замена текста по шаблону
replace и replaceFirst работают как «найти и заменить» в текстовом редакторе, только автоматически. В строке-заменителе можно ссылаться на группы через $1, $2. Например, поменяем дату с формата ДД/ММ/ГГГГ на ГГГГ-ММ-ДД.
val dateText = "Событие: 09/05/2026"
val newDate = datePattern.replace(dateText) { match ->
"${match.groupValues[3]}-${match.groupValues[2]}-${match.groupValues[1]}"
}
println(newDate) // "Событие: 2026-05-09"
Для замены всех лишних пробелов на один достаточно шаблона \s+:
val spaced = "Это слишком много пробелов"
val clean = "\\s+".toRegex().replace(spaced, " ")
println(clean) // "Это слишком много пробелов"
Разделение строки
Метод split принимает Regex и режет строку в каждом месте совпадения. В отличие от обычного split с символом, здесь можно задать сложный разделитель: несколько запятых подряд, пробелы или любой символ.
val csv = "apple;banana,,orange"
val items = "[;,]".toRegex().split(csv).filter { it.isNotEmpty() }
println(items) // ["apple", "banana", "orange"]
Если разделителей несколько видов, шаблон "[,;]".toRegex() обработает их все за один проход. Не забывайте фильтровать пустые строки, которые могут появиться при повторяющихся разделителях.
Коротко о главном
Kotlin регулярные выражения — это компактный и гибкий инструмент для обработки текста. Вы научились создавать Regex через toRegex(), проверять строки с matches и containsMatchIn, извлекать данные через find и findAll, а также заменять и разделять текст. Начните с простых шаблонов: валидация email, поиск чисел, уборка лишних пробелов — и постепенно двигайтесь к более сложным выражениям. Запомните главное: регулярка не страшна, если разбирать её по кусочкам.