Регулярные выражения в Swift: от основ до продвинутых примеров
Регулярные выражения (regex) — мощный инструмент для работы с текстом, позволяющий искать, заменять и проверять строки по сложным шаблонам. В Swift для iOS и macOS работа с регулярками реализована через класс NSRegularExpression из фреймворка Foundation. В этой статье мы разберём все ключевые аспекты: от создания простейших шаблонов до обработки результатов и оптимизации производительности.
Статья будет полезна как новичкам, только знакомящимся со Swift, так и опытным разработчикам, желающим углубить знания по работе с текстом в iOS/macOS приложениях.
1. Основы работы с NSRegularExpression
Класс NSRegularExpression — основной инструмент для работы с регулярными выражениями в Swift. Он предоставляет методы для поиска, замены и извлечения данных из строк.
1.1. Создание регулярного выражения
Для создания объекта NSRegularExpression используется инициализатор, который принимает строку с шаблоном и опциональные флаги (NSRegularExpression.Options). Конструкция обёрнута в try, так как может выбросить ошибку при некорректном синтаксисе шаблона.
import Foundation
let pattern = "\\d{3}-\\d{2}-\\d{4}" // Пример: 123-45-6789
do {
let regex = try NSRegularExpression(pattern: pattern, options: [])
print("Регулярное выражение создано успешно")
} catch {
print("Ошибка в синтаксисе регулярного выражения: \(error.localizedDescription)")
}
1.2. Основные опции (NSRegularExpression.Options)
Опции позволяют изменить поведение регулярного выражения. Вот наиболее часто используемые:
.caseInsensitive— игнорирование регистра символов (A = a)..allowCommentsAndWhitespace— игнорировать пробелы и комментарии в шаблоне..dotMatchesLineSeparators— точка (.) также соответствует символам переноса строки..anchorsMatchLines— символы ^ и $ соответствуют началу и концу каждой строки, а не всей строки.
Пример с опцией .caseInsensitive:
let pattern = "hello"
let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let testString = "Hello, World!"
let range = NSRange(location: 0, length: testString.utf16.count)
if regex.firstMatch(in: testString, options: [], range: range) != nil {
print("Найдено совпадение") // Выведет: Найдено совпадение
}
2. Поиск совпадений и работа с результатами
После создания регулярного выражения можно выполнять поиск совпадений в строке. Для этого используются методы firstMatch и matches.
2.1. Поиск первого совпадения
Метод firstMatch(in:options:range:) возвращает первое найденное совпадение в виде объекта NSTextCheckingResult (или nil, если ничего не найдено).
let text = "Мой номер: 123-45-6789, а также 987-65-4321"
let pattern = "\\d{3}-\\d{2}-\\d{4}"
let regex = try NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(location: 0, length: text.utf16.count)
if let match = regex.firstMatch(in: text, options: [], range: range) {
let matchedString = (text as NSString).substring(with: match.range)
print("Первое совпадение: \(matchedString)") // 123-45-6789
}
2.2. Поиск всех совпадений
Метод matches(in:options:range:) возвращает массив всех совпадений. Это полезно, когда нужно обработать каждое вхождение шаблона.
let text = "Коды: ABC-123, DEF-456, GHI-789"
let pattern = "[A-Z]{3}-\\d{3}"
let regex = try NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(location: 0, length: text.utf16.count)
let matches = regex.matches(in: text, options: [], range: range)
for match in matches {
let code = (text as NSString).substring(with: match.range)
print("Найден код: \(code)")
}
// Вывод:
// Найден код: ABC-123
// Найден код: DEF-456
// Найден код: GHI-789
2.3. Извлечение групп (capture groups)
Группы в регулярных выражениях (обозначаются круглыми скобками) позволяют извлекать части совпадения. Доступ к группам осуществляется через range(at:).
let text = "Имя: Иван, возраст: 25"
let pattern = "Имя: (\\w+), возраст: (\\d+)"
let regex = try NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(location: 0, length: text.utf16.count)
if let match = regex.firstMatch(in: text, options: [], range: range) {
let nameRange = match.range(at: 1)
let ageRange = match.range(at: 2)
let name = (text as NSString).substring(with: nameRange)
let age = (text as NSString).substring(with: ageRange)
print("Имя: \(name), возраст: \(age)") // Имя: Иван, возраст: 25
}
3. Замена текста с помощью регулярных выражений
Класс NSRegularExpression предоставляет два метода для замены: stringByReplacingMatches (возвращает новую строку) и replaceMatches (изменяет исходную NSMutableString).
3.1. Простая замена
Пример замены всех номеров телефонов на текст "[СКРЫТО]":
let originalText = "Позвоните по номеру 123-45-6789 или 987-65-4321"
let pattern = "\\d{3}-\\d{2}-\\d{4}"
let regex = try NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(location: 0, length: originalText.utf16.count)
let modifiedText = regex.stringByReplacingMatches(
in: originalText,
options: [],
range: range,
withTemplate: "[СКРЫТО]"
)
print(modifiedText) // Позвоните по номеру [СКРЫТО] или [СКРЫТО]
3.2. Замена с использованием групп
Можно ссылаться на группы в шаблоне замены с