Регулярные выражения в Kotlin: полное руководство с примерами
Регулярные выражения (regex) — мощный инструмент для поиска, извлечения и замены текста по шаблону. В Kotlin работа с регулярками реализована через класс Regex, который предоставляет удобный API и полную совместимость с Java-реализацией java.util.regex.Pattern. В этой статье мы разберем все аспекты использования регулярных выражений в Kotlin с наглядными примерами.
1. Создание и базовое использование Regex в Kotlin
В Kotlin есть два основных способа создать регулярное выражение:
- Конструктор класса
Regex— передаете строку с шаблоном. - Метод-расширение
.toRegex()— вызывается на строке.
Примеры создания:
// Способ 1: конструктор
val regex1 = Regex("\\d{3}-\\d{2}-\\d{4}")
// Способ 2: toRegex()
val regex2 = "\\d{3}-\\d{2}-\\d{4}".toRegex()
// С флагами (регистронезависимый поиск)
val regex3 = Regex("hello", RegexOption.IGNORE_CASE)
// Многострочный режим
val regex4 = Regex("^start", RegexOption.MULTILINE)
Обратите внимание: в Kotlin, как и в Java, для экранирования обратного слеша используется двойной слеш \\. Если вы пишете \d — нужно писать "\\d".
2. Основные функции Regex: проверка, поиск, замена
Класс Regex предоставляет несколько ключевых функций для работы со строками.
2.1. Проверка полного совпадения — matches()
Функция matches() возвращает true, если вся строка целиком соответствует шаблону.
val emailRegex = Regex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}")
val email1 = "user@example.com"
val email2 = "invalid-email"
println(emailRegex.matches(email1)) // true
println(emailRegex.matches(email2)) // false
2.2. Поиск первого совпадения — find()
Возвращает первое найденное совпадение в виде объекта MatchResult? (или null, если ничего не найдено).
val text = "Мой телефон: 123-45-6789 и еще 987-65-4321"
val phoneRegex = Regex("\\d{3}-\\d{2}-\\d{4}")
val firstMatch = phoneRegex.find(text)
if (firstMatch != null) {
println("Найден телефон: ${firstMatch.value}") // Найден телефон: 123-45-6789
println("Начало: ${firstMatch.range.first}") // Начало: 13
}
2.3. Поиск всех совпадений — findAll()
Возвращает последовательность Sequence<MatchResult> всех непересекающихся совпадений.
val text = "Цены: 100 руб., 250 руб., 50 руб."
val priceRegex = Regex("\\d+")
val prices = priceRegex.findAll(text)
prices.forEach { match ->
println("Цена: ${match.value}")
}
// Вывод:
// Цена: 100
// Цена: 250
// Цена: 50
2.4. Замена по шаблону — replace()
Функция replace() заменяет все найденные совпадения на указанную строку или результат лямбда-выражения.
val text = "Мой email: john@mail.com и support@site.org"
val emailRegex = Regex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}")
// Простая замена
val masked = emailRegex.replace(text, "[EMAIL HIDDEN]")
println(masked) // Мой email: [EMAIL HIDDEN] и [EMAIL HIDDEN]
// Замена с лямбдой (динамическая)
val replaced = emailRegex.replace(text) { match ->
val local = match.value.split("@")[0]
"${local.first()}***@***"
}
println(replaced) // Мой email: j***@*** и s***@***
2.5. Разделение строки — split()
Разбивает строку по совпадениям с регулярным выражением.
val text = "яблоко,груша;банан|апельсин"
val separators = Regex("[,;|]")
val fruits = separators.split(text)
println(fruits) // [яблоко, груша, банан, апельсин]
3. Работа с группами захвата
Группы захвата позволяют извлекать части совпадения. В Kotlin к группам обращаются по индексу (начиная с 1) или по имени (если задано).
val dateStr = "Сегодня 15.03.2024, вчера было 14.03.2024"
val dateRegex = Regex("(\\d{2})\\.(\\d{2})\\.(\\d{4})")
// Извлекаем первую дату
val firstDate = dateRegex.find(dateStr)
if (firstDate != null) {
println("Полная дата: ${firstDate.value}") // 15.03.2024
println("День: ${firstDate.groupValues[1]}") // 15
println("Месяц: ${firstDate.groupValues[2]}") // 03
println("Год: ${firstDate.groupValues[3]}") // 2024
}
Именованные группы (синтаксис (?<name>...)):
val namedRegex = Regex("(?<day>\\d{2})\\.(?<month>\\d{2})\\.(?<year>\\d{4})")
val match = namedRegex.find("Дата: 25.12.2023")
if (match != null) {
println("День: ${match.groups["day"]?.value}") // 25
println("Месяц: ${match.groups["month"]?.value}") // 12
println("Год: ${match.groups["year"]?.value}") // 2023
}
4. Продвинутые возможности и флаги
4.1. Флаги регулярных выражений
Kotlin поддерживает все стандартные флаги через enum RegexOption:
| Флаг | Описание |
|---|---|