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

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

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

Начать курс

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

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

Основы работы с NSRegularExpression в Swift

Класс NSRegularExpression предоставляет все необходимые методы для работы с регулярными выражениями. Базовый алгоритм работы включает три шага:

  1. Создание объекта шаблона регулярного выражения
  2. Применение шаблона к строке
  3. Обработка результатов (совпадений, замен)

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

Вот как создать и применить простейшее регулярное выражение для поиска слова "Swift":

import Foundation

let text = "Изучаем Swift и iOS разработку"
let pattern = "Swift"

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)")
}

Обратите внимание на преобразование Range — это стандартный способ работы с позициями в строках Swift. Результат выполнения: "Найдено: Swift".

Практический пример 1: Поиск email-адресов

Одна из самых частых задач — извлечение email-адресов из текста. Рассмотрим пример, который найдет все email в строке:

import Foundation

func findEmails(in text: String) -> [String] {
    let pattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
    var emails: [String] = []
    
    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) {
                emails.append(String(text[range]))
            }
        }
    } catch {
        print("Ошибка: \(error)")
    }
    
    return emails
}

// Пример использования
let sampleText = "Контакты: support@example.com и admin@site.org"
let foundEmails = findEmails(in: sampleText)
print(foundEmails) // ["support@example.com", "admin@site.org"]

Этот шаблон учитывает стандартные символы, разрешенные в email, и проверяет наличие точки в доменной части. Для продакшена можно добавить поддержку кириллических доменов.

Практический пример 2: Валидация номера телефона

Валидация вводимых данных — важная часть любого приложения. Вот как проверить российский номер телефона в формате +7 (XXX) XXX-XX-XX:

import Foundation

func isValidPhoneNumber(_ phone: String) -> Bool {
    // Шаблон для российского номера: +7 (XXX) XXX-XX-XX
    let pattern = "^\\+7\\s?\\(?[0-9]{3}\\)?\\s?[0-9]{3}-?[0-9]{2}-?[0-9]{2}$"
    
    do {
        let regex = try NSRegularExpression(pattern: pattern)
        let range = NSRange(location: 0, length: phone.utf16.count)
        return regex.firstMatch(in: phone, range: range) != nil
    } catch {
        return false
    }
}

// Тестирование
let validNumbers = ["+7 (495) 123-45-67", "+74951234567", "+7 495 1234567"]
let invalidNumbers = ["8 (495) 123-45-67", "+7 (495) 123-45-678", "abc"]

for number in validNumbers {
    print("\(number): \(isValidPhoneNumber(number))") // true
}

for number in invalidNumbers {
    print("\(number): \(isValidPhoneNumber(number))") // false
}

Шаблон использует якоря ^ и $ для проверки всей строки, что исключает частичное совпадение. Это критично для валидации.

Практический пример 3: Замена и извлечение данных

Регулярные выражения отлично подходят для замены подстрок. Например, можно заменить все даты в формате "дд.мм.гггг" на "гггг-мм-дд":

import Foundation

func reformatDates(in text: String) -> String {
    let pattern = "(\\d{2})\\.(\\d{2})\\.(\\d{4})"
    let replacement = "$3-$2-$1"
    
    do {
        let regex = try NSRegularExpression(pattern: pattern)
        let range = NSRange(text.startIndex..., in: text)
        let result = regex.stringByReplacingMatches(in: text, range: range, withTemplate: replacement)
        return result
    } catch {
        return text
    }
}

// Пример
let input = "Сегодня 15.03.2024, завтра 16.03.2024"
let output = reformatDates(in: input)
print(output) // "Сегодня 2024-03-15, завтра 2024-03-16"

Здесь используются группы захвата () и обратные ссылки $1, $2, $3. Это мощный механизм для перестановки частей текста.

Извлечение данных с помощью групп

Часто нужно не просто найти совпадение, а извлечь его части. Например, разбор URL на компоненты:

import Foundation

struct URLComponents {
    let scheme: String
    let host: String
    let path: String
}

func parseURL(_ url: String) -> URLComponents? {
    let pattern = "^(https?)://([A-Za-z0-9.-]+)(/[A-Za-z0-9/.-]*)?$"
    
    do {
        let regex = try NSRegularExpression(pattern: pattern)
        let range = NSRange(url.startIndex..., in: url)
        
        if let match = regex.firstMatch(in: url, range: range) {
            let schemeRange = Range(match.range(at: 1), in: url)!
            let hostRange = Range(match.range(at: 2), in: url)!
            let pathRange = match.range(at: 3).location != NSNotFound ? Range(match.range(at: 3), in: url) : nil
            
            return URLComponents(
                scheme: String(url[schemeRange]),
                host: String(url[hostRange]),
                path: pathRange != nil ? String(url[pathRange!]) : ""
            )
        }
    } catch {
        print("Ошибка парсинга URL: \(error)")
    }
    
    return nil
}

// Пример
if let components = parseURL                

Блоги

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