Регулярные выражения в Swift: полное руководство для новичков
Регулярные выражения (regex) — это мощный инструмент для поиска, замены и валидации текстовых данных. В Swift работа с регулярными выражениями реализована через класс NSRegularExpression из фреймворка Foundation. В этой статье вы научитесь создавать и применять регулярные выражения в приложениях для iOS и macOS, разберете реальные примеры и освоите основы синтаксиса.
1. Основы синтаксиса регулярных выражений
Прежде чем писать код на Swift, важно понять базовые символы и конструкции regex. Вот ключевые элементы:
.— любой символ (кроме перевода строки)*— 0 или более повторений предыдущего символа+— 1 или более повторений?— 0 или 1 повторение (делает предыдущий символ необязательным)\d— любая цифра (0-9)\w— любая буква, цифра или подчеркивание[abc]— один из символов a, b или c[^abc]— любой символ, кроме a, b, c^— начало строки$— конец строки
Эти символы комбинируются для создания шаблонов. Например, шаблон ^[A-Za-z]+$ означает: строка состоит только из букв латинского алфавита от начала до конца.
2. Создание и использование NSRegularExpression в Swift
В Swift работа с regex начинается с импорта Foundation и создания экземпляра NSRegularExpression. Рассмотрим простой пример: поиск всех цифр в строке.
import Foundation
let text = "Мой номер: 123-456-7890"
let pattern = "\\d+" // шаблон: одна или более цифр
do {
let regex = try NSRegularExpression(pattern: pattern)
let results = regex.matches(in: text, range: NSRange(text.startIndex..., in: text))
for match in results {
if let range = Range(match.range, in: text) {
print("Найдено: \(text[range])")
}
}
} catch {
print("Ошибка в регулярном выражении: \(error.localizedDescription)")
}
// Вывод:
// Найдено: 123
// Найдено: 456
// Найдено: 7890
Обратите внимание на экранирование обратной косой черты: в Swift строке "\\d" соответствует регулярному выражению \d. Класс NSRegularExpression выбрасывает исключение при неверном шаблоне, поэтому используем try-catch.
2.1. Работа с NSRange
Метод matches(in:range:) возвращает массив объектов NSTextCheckingResult. Каждый результат содержит диапазон (NSRange) найденного совпадения. Для преобразования в Swift Range используйте инициализатор Range(match.range, in: text).
3. Практические примеры регулярных выражений
Рассмотрим три типичные задачи: проверка email, извлечение URL и замена текста.
3.1. Валидация email-адреса
Проверим, соответствует ли строка простому шаблону email (упрощенный вариант):
func isValidEmail(_ email: String) -> Bool {
let pattern = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
let regex = try? NSRegularExpression(pattern: pattern)
let range = NSRange(location: 0, length: email.utf16.count)
return regex?.firstMatch(in: email, range: range) != nil
}
print(isValidEmail("test@example.com")) // true
print(isValidEmail("invalid-email")) // false
Здесь мы используем firstMatch, который возвращает первое совпадение. Если совпадений нет — возвращается nil.
3.2. Извлечение URL из текста
Допустим, у нас есть строка с несколькими ссылками. Извлечем все URL:
let text = "Посетите сайт https://pythonlib.ru или напишите на support@pythonlib.ru"
let pattern = "https?://[\\w./%-]+"
do {
let regex = try NSRegularExpression(pattern: pattern)
let matches = regex.matches(in: text, range: NSRange(text.startIndex..., in: text))
var urls: [String] = []
for match in matches {
if let range = Range(match.range, in: text) {
urls.append(String(text[range]))
}
}
print("Найденные URL: \(urls)")
} catch {
print("Ошибка: \(error)")
}
// Вывод: Найденные URL: ["https://pythonlib.ru"]
Обратите внимание: шаблон https?:// соответствует как http://, так и https://. Символ ? делает букву 's' необязательной.
3.3. Замена текста с помощью regex
Метод stringByReplacingMatches позволяет заменить все совпадения на указанную строку:
let originalText = "Сегодня 15.03.2024, а завтра 16.03.2024"
let pattern = "(\\d{2})\\.(\\d{2})\\.(\\d{4})"
let replacement = "$3-$2-$1" // меняем формат на ГГГГ-ММ-ДД
let regex = try? NSRegularExpression(pattern: pattern)
let modifiedText = regex?.stringByReplacingMatches(
in: originalText,
range: NSRange(originalText.startIndex..., in: originalText),
withTemplate: replacement
) ?? originalText
print(modifiedText)
// Вывод: Сегодня 2024-03-15, а завтра 2024-03-16
В шаблоне используются группы захвата (круглые скобки). В строке замены $1, $2, $3 ссылаются на первую, вторую и третью группы соответственно. Это позволяет переставлять части даты.
4. Продвинутые возможности и советы
Вот несколько дополнительных аспектов, которые помогут вам эффективно работать с regex в Swift:
- Опции регулярного выражения: Второй параметр
NSRegularExpression— массив опций. Например,.caseInsensitiveдля игнорирования регистра,.dotMatchesLineSepar