Регулярные выражения в Swift: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Регулярные выражения в Swift: мощный инструмент для работы с текстом

Регулярные выражения (regex) — это незаменимый инструмент для разработчиков iOS и macOS. Они позволяют выполнять сложный поиск, замену и валидацию текстовых данных с помощью компактных шаблонов. В Swift работа с регулярными выражениями реализована через класс NSRegularExpression из Foundation framework. В этой статье мы разберем все аспекты использования regex в Swift: от базового синтаксиса до продвинутых техник, с практическими примерами для iOS и macOS приложений.

Основы NSRegularExpression в Swift

Для работы с регулярными выражениями в Swift используется класс NSRegularExpression. Он предоставляет мощные методы для поиска, замены и извлечения данных из строк. Рассмотрим базовый синтаксис инициализации:

import Foundation

let pattern = "\\d{3}-\\d{2}-\\d{4}" // Шаблон для SSN
let text = "Мой SSN: 123-45-6789"

do {
    let regex = try NSRegularExpression(pattern: pattern)
    let results = regex.matches(in: text, range: NSRange(text.startIndex..., in: text))
    
    for match in results {
        let range = Range(match.range, in: text)!
        print("Найдено: \(text[range])")
    }
} catch {
    print("Ошибка в регулярном выражении: \(error.localizedDescription)")
}

Обратите внимание на экранирование обратной косой черты в Swift-строках. Для каждого обратного слеша в шаблоне нужно ставить два (\\d вместо \d).

Создание и настройка регулярного выражения

Конструктор NSRegularExpression принимает опциональный параметр options, который позволяет настроить поведение regex:

  • .caseInsensitive — игнорировать регистр символов
  • .dotMatchesLineSeparators — точка соответствует символам перевода строки
  • .anchorsMatchLines — якоря ^ и $ работают для каждой строки
  • .useUnixLineSeparators — использовать только \n как разделитель строк
let regex = try NSRegularExpression(
    pattern: "swift",
    options: [.caseInsensitive]
)
// Теперь шаблон найдет "Swift", "SWIFT", "swift" и т.д.

Поиск и извлечение данных с помощью regex

Одна из главных задач регулярных выражений — поиск подстрок, соответствующих шаблону. В Swift это делается через метод matches(in:options:range:).

Поиск всех совпадений

let text = "Контакты: email@example.com, support@test.org, admin@site.com"
let emailPattern = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"

let regex = try NSRegularExpression(pattern: emailPattern)
let matches = regex.matches(in: text, range: NSRange(text.startIndex..., in: text))

print("Найдено email: \(matches.count)")
for match in matches {
    if let range = Range(match.range, in: text) {
        print(String(text[range]))
    }
}
// Вывод:
// Найдено email: 3
// email@example.com
// support@test.org
// admin@site.com

Поиск с захватом групп

Группы в круглых скобках позволяют извлекать части совпадения. Это особенно полезно для парсинга структурированных данных:

let logLine = "2024-01-15 14:30:22 [ERROR] Не удалось подключиться к серверу"
let logPattern = "(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2}:\\d{2}) \\[(\\w+)\\] (.+)"

let regex = try NSRegularExpression(pattern: logPattern)
if let match = regex.firstMatch(in: logLine, range: NSRange(logLine.startIndex..., in: logLine)) {
    let dateRange = Range(match.range(at: 1), in: logLine)!
    let timeRange = Range(match.range(at: 2), in: logLine)!
    let levelRange = Range(match.range(at: 3), in: logLine)!
    let messageRange = Range(match.range(at: 4), in: logLine)!
    
    print("Дата: \(logLine[dateRange])")
    print("Время: \(logLine[timeRange])")
    print("Уровень: \(logLine[levelRange])")
    print("Сообщение: \(logLine[messageRange])")
}

Замена текста с помощью регулярных выражений

Метод stringByReplacingMatches(in:options:range:withTemplate:) позволяет выполнять замену по шаблону. Это мощный инструмент для очистки и трансформации текста.

Простая замена

let originalText = "Мой номер телефона: 8-800-555-35-35"
let phonePattern = "\\d-\\d{3}-\\d{3}-\\d{2}-\\d{2}"
let replacement = "[ТЕЛЕФОН СКРЫТ]"

let regex = try NSRegularExpression(pattern: phonePattern)
let maskedText = regex.stringByReplacingMatches(
    in: originalText,
    range: NSRange(originalText.startIndex..., in: originalText),
    withTemplate: replacement
)
print(maskedText) // "Мой номер телефона: [ТЕЛЕФОН СКРЫТ]"

Замена с использованием групп

Шаблоны замены могут ссылаться на захваченные группы с помощью $1, $2 и т.д.:

let text = "Иванов Иван, Петров Петр, Сидоров Алексей"
let namePattern = "(\\w+) (\\w+)"
let replacementTemplate = "$2 $1" // Меняем местами фамилию и имя

let regex = try NSRegularExpression(pattern: namePattern)
let result = regex.stringByReplacingMatches(
    in: text,
    range: NSRange(text.startIndex..., in: text),
    withTemplate: replacementTemplate
)
print(result) // "Иван Иванов, Петр Петров, Алексей Сидоров"

Валидация данных с помощью regex

Регулярные выражения идеально подходят для проверки корректности вводимых данных. Вот несколько практических примеров для iOS-приложений:

Валидация email

func isValidEmail(_ email: String) -> Bool {
    let emailPattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
    let predicate = NSPredicate(format: "SELF MATCHES %@", emailPattern)
    return predicate.evaluate(with: email)
}

print(isValidEmail("user@example.com")) // true
print(isValidEmail("invalid                

Блоги

Рекомендаций по книгам