Извлечение совпадений регулярных выражений в Swift
Решение с NSRegularExpression и группами захвата
В Swift для извлечения групп захвата из регулярных выражений используется класс NSRegularExpression в паре с NSTextCheckingResult. Вот полное решение вашей задачи:
import Foundation
let text = "Привет, меня зовут Иван, мне 25 лет, я живу в Москве"
let pattern = "зовут (\\w+), мне (\\d+), в (\\w+)"
do {
let regex = try NSRegularExpression(pattern: pattern)
let nsRange = NSRange(text.startIndex..<text.endIndex, in: text)
if let match = regex.firstMatch(in: text, range: nsRange) {
// Извлекаем группы захвата
let nameRange = Range(match.range(at: 1), in: text)!
let ageRange = Range(match.range(at: 2), in: text)!
let cityRange = Range(match.range(at: 3), in: text)!
let name = String(text[nameRange])
let age = String(text[ageRange])
let city = String(text[cityRange])
print("Имя: \(name), Возраст: \(age), Город: \(city)")
}
} catch {
print("Ошибка регулярного выражения: \(error.localizedDescription)")
}
// Вывод: Имя: Иван, Возраст: 25, Город: Москве
Пояснение ключевых моментов
- Группы захвата: В паттерне используются круглые скобки
()для создания групп. Нумерация групп начинается с 1 (группа 0 — всё совпадение целиком). - Экранирование: В Swift-строках обратный слеш экранируется двойным слэшем:
\\wвместо\w. - NSRange vs Range:
NSTextCheckingResultработает сNSRange, но мы конвертируем его в SwiftRange<String.Index>для безопасной работы сString. - Метод firstMatch: Используем
firstMatch, если нужно только первое совпадение. Для всех совпадений применяйтеmatches.
Обработка нескольких совпадений
Если строка содержит несколько записей, используйте matches:
let text = "Иван 25, Мария 30, Петр 40"
let pattern = "(\\w+) (\\d+)"
do {
let regex = try NSRegularExpression(pattern: pattern)
let matches = regex.matches(in: text, range: NSRange(text.startIndex..., in: text))
for match in matches {
let name = String(text[Range(match.range(at: 1), in: text)!])
let age = String(text[Range(match.range(at: 2), in: text)!])
print("\(name): \(age)")
}
} catch {
print(error)
}
// Вывод:
// Иван: 25
// Мария: 30
// Петр: 40
Современный Swift 5.7+ (Regex literals)
Начиная с Swift 5.7, появился встроенный тип Regex с поддержкой литералов:
import RegexBuilder
let text = "Привет, меня зовут Иван, мне 25 лет, я живу в Москве"
let regex = /зовут (\w+), мне (\d+), в (\w+)/
if let match = text.firstMatch(of: regex) {
let (_, name, age, city) = match.output
print("Имя: \(name), Возраст: \(age), Город: \(city)")
}
// Вывод: Имя: Иван, Возраст: 25, Город: Москве
Также можно использовать RegexBuilder для более сложных паттернов:
import RegexBuilder
let nameRef = Reference(String.self)
let ageRef = Reference(String.self)
let cityRef = Reference(String.self)
let regex = Regex {
"зовут "
Capture(as: nameRef) { OneOrMore(.word) }
", мне "
Capture(as: ageRef) { OneOrMore(.digit) }
", в "
Capture(as: cityRef) { OneOrMore(.word) }
}
if let match = text.firstMatch(of: regex) {
print("Имя: \(match[nameRef]), Возраст: \(match[ageRef]), Город: \(match[cityRef])")
}
Рекомендация: Для проектов на Swift 5.7+ используйте Regex литералы — это чище и безопаснее. Для обратной совместимости остаётся NSRegularExpression.
Альтернативный подход: разбиение строки и компоненты
Если ваша задача не требует сложных регулярных выражений, можно обойтись стандартными методами String и Scanner. Это часто проще для новичков.
Решение с Scanner
import Foundation
let text = "Привет, меня зовут Иван, мне 25 лет, я живу в Москве"
let scanner = Scanner(string: text)
// Пропускаем "Привет, меня зовут "
_ = scanner.scanUpToString("зовут ")
scanner.scanString("зовут ")
let name = scanner.scanUpToString(", мне") ?? ""
scanner.scanString(", мне ")
let age = scanner.scanInt() ?? 0
_ = scanner.scanString(" лет, я живу в ")
let city = scanner.scanUpToString("") ?? ""
print("Имя: \(name), Возраст: \(age), Город: \(city)")
Решение с разделением строки
let text = "Привет, меня зовут Иван, мне 25 лет, я живу в Москве"
let parts = text.components(separatedBy: ", ")
if parts.count >= 3 {
let namePart = parts[1] // "меня зовут Иван"
let agePart = parts[2] // "мне 25 лет"
let cityPart = parts[3] // "я живу в Москве"
let name = namePart.components(separatedBy: " ").last ?? ""
let age = agePart.components(separatedBy: " ")[1]
let city = cityPart.components(separatedBy: " ").last ?? ""
print("Имя: \(name), Возраст: \(age), Город: \(city)")
}
Эти методы менее гибкие, чем регулярные выражения, но для простых и стабильных форматов данных они работают отлично и не требуют изучения синтаксиса regex.
Ответов пока нет.
Войдите чтобы оставить ответ