Регулярные выражения в Rust: полное руководство для начинающих

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

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

Начать курс

Введение в регулярные выражения в Rust

Регулярные выражения (regex) — это мощный инструмент для поиска, извлечения и замены текста по заданному шаблону. В Rust для работы с регулярными выражениями используется крейт regex — одна из самых популярных и производительных библиотек экосистемы. В этой статье мы разберём основы работы с regex в Rust, начиная с установки и заканчивая практическими примерами.

Почему стоит изучить регулярные выражения в Rust? Язык предлагает безопасную и быструю работу с текстом, а крейт regex гарантирует отсутствие утечек памяти и высокую скорость выполнения. Это делает Rust отличным выбором для парсинга логов, валидации форм, обработки конфигурационных файлов и других задач.

Установка и подключение крейта regex

Для начала работы добавьте зависимость regex в ваш файл Cargo.toml:

[dependencies]
regex = "1.10"

После этого импортируйте модуль в коде:

use regex::Regex;

Основная структура, с которой вы будете работать — Regex. Создать экземпляр можно с помощью метода Regex::new(), который возвращает Result, так как шаблон может быть некорректным.

fn main() {
    let re = Regex::new(r"^\d{3}-\d{2}-\d{4}$").unwrap();
    println!("Regex создан: {}", re.as_str());
}

Обратите внимание: шаблон записывается в сырых строках (r"..."), чтобы избежать экранирования обратных слешей.

Основные операции с регулярными выражениями

1. Проверка совпадения: is_match

Метод is_match возвращает true, если шаблон найден в строке:

use regex::Regex;

fn main() {
    let re = Regex::new(r"hello").unwrap();
    let text = "hello world";
    
    if re.is_match(text) {
        println!("Совпадение найдено!");
    } else {
        println!("Совпадений нет");
    }
}

Вывод: Совпадение найдено!

2. Поиск первого совпадения: find

Метод find возвращает Option<Match> — первое совпадение с информацией о позиции:

use regex::Regex;

fn main() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "Код: 12345, цена: 678";
    
    if let Some(m) = re.find(text) {
        println!("Найдено: '{}' (позиция {}..{})", m.as_str(), m.start(), m.end());
    }
}

Вывод: Найдено: '12345' (позиция 5..10)

3. Поиск всех совпадений: find_iter

Для получения всех совпадений используйте итератор find_iter:

use regex::Regex;

fn main() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "Числа: 42, 100, 7";
    
    for m in re.find_iter(text) {
        println!("Число: {}", m.as_str());
    }
}

Вывод:

Число: 42
Число: 100
Число: 7

4. Извлечение групп: captures

Группы в шаблоне (обозначаются круглыми скобками) позволяют извлекать части совпадения:

use regex::Regex;

fn main() {
    let re = Regex::new(r"(\w+)@(\w+)\.(\w+)").unwrap();
    let email = "user@example.com";
    
    if let Some(caps) = re.captures(email) {
        println!("Полный email: {}", &caps[0]);
        println!("Имя: {}", &caps[1]);
        println!("Домен: {}", &caps[2]);
        println!("Зона: {}", &caps[3]);
    }
}

Вывод:

Полный email: user@example.com
Имя: user
Домен: example
Зона: com

Практические примеры использования

Пример 1: Валидация телефонного номера

Проверим, соответствует ли строка формату российского номера (например, +7-XXX-XXX-XX-XX):

use regex::Regex;

fn validate_phone(phone: &str) -> bool {
    let re = Regex::new(r"^\+7-\d{3}-\d{3}-\d{2}-\d{2}$").unwrap();
    re.is_match(phone)
}

fn main() {
    let phones = vec!["+7-999-123-45-67", "8-999-123-45-67", "+7-999-12-345"];
    
    for phone in phones {
        println!("{}: {}", phone, validate_phone(phone));
    }
}

Вывод:

+7-999-123-45-67: true
8-999-123-45-67: false
+7-999-12-345: false

Пример 2: Извлечение URL из текста

use regex::Regex;

fn extract_urls(text: &str) -> Vec<String> {
    let re = Regex::new(r"https?://[^\s]+").unwrap();
    re.find_iter(text)
        .map(|m| m.as_str().to_string())
        .collect()
}

fn main() {
    let text = "Посетите https://rust-lang.org и http://example.com для обучения.";
    let urls = extract_urls(text);
    
    println!("Найденные URL:");
    for url in urls {
        println!("  {}", url);
    }
}

Вывод:

Найденные URL:
  https://rust-lang.org
  http://example.com

Пример 3: Замена текста по шаблону

Метод replace заменяет первое совпадение, а replace_all — все:

use regex::Regex;

fn main() {
    let re = Regex::new(r"\bRust\b").unwrap();
    let text = "Rust — это язык программирования. Я люблю Rust!";
    
    let result = re.replace_all(text, "Rust🦀");
    println!("{}", result);
}

Вывод: Rust🦀 — это язык программирования. Я люблю Rust🦀!

Советы по производительности

Крейт regex в Rust очень быст

Блоги

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