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

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

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

Начать курс

Регулярные выражения в Go с примерами

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

1. Основы пакета regexp

Пакет regexp предоставляет два основных подхода: быстрое однократное использование (функции уровня пакета) и производительная работа с предварительно скомпилированным шаблоном (структура Regexp). Для многократного использования всегда компилируйте шаблон заранее.

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

package main

import (
    "fmt"
    "regexp"
)

func main() {
    // Компиляция шаблона (рекомендуемый способ с обработкой ошибки)
    pattern, err := regexp.Compile(`\d+`)
    if err != nil {
        fmt.Println("Ошибка компиляции:", err)
        return
    }
    
    // Для простых случаев — без обработки ошибок (паника при невалидном шаблоне)
    patternMust := regexp.MustCompile(`[a-z]+`)
    
    fmt.Println(pattern, patternMust)
}

Compile возвращает ошибку, если шаблон невалиден. MustCompile вызывает панику — используйте его только для статических шаблонов.

2. Базовые операции: поиск и проверка

Рассмотрим основные методы для проверки соответствия и поиска подстрок.

Проверка на частичное совпадение

pattern := regexp.MustCompile(`go`)
text := "Я изучаю Golang"

// MatchString — содержит ли строка подстроку, соответствующую шаблону
matched := pattern.MatchString(text)
fmt.Println(matched) // true (так как "go" содержится в "Golang")

Проверка на полное совпадение

// Для проверки, что вся строка соответствует шаблону, используйте якоря ^ и $
fullPattern := regexp.MustCompile(`^[a-zA-Z]+$`)
fmt.Println(fullPattern.MatchString("Hello"))   // true
fmt.Println(fullPattern.MatchString("Hello1"))  // false

Поиск первого совпадения

datePattern := regexp.MustCompile(`\d{2}\.\d{2}\.\d{4}`)
text := "Сегодня 15.03.2024, а завтра 16.03.2024"

// FindString — возвращает первое совпадение
firstDate := datePattern.FindString(text)
fmt.Println(firstDate) // "15.03.2024"

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

// FindAllString — возвращает срез всех совпадений
allDates := datePattern.FindAllString(text, -1) // -1 — все совпадения
fmt.Println(allDates) // ["15.03.2024" "16.03.2024"]

// Ограничение количества: FindAllString(text, 1) — только первое

3. Группы захвата и подстановки

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

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

// Шаблон для извлечения имени и возраста: "Имя: [имя], Возраст: [число]"
personPattern := regexp.MustCompile(`Имя: (\w+), Возраст: (\d+)`)
text := "Имя: Алексей, Возраст: 30"

// FindStringSubmatch — возвращает срез: [всё_совпадение, группа1, группа2, ...]
matches := personPattern.FindStringSubmatch(text)
if len(matches) > 0 {
    fmt.Println("Полное совпадение:", matches[0]) // "Имя: Алексей, Возраст: 30"
    fmt.Println("Имя:", matches[1])                // "Алексей"
    fmt.Println("Возраст:", matches[2])            // "30"
}

Именованные группы (Go 1.21+)

// С версии Go 1.21 можно использовать именованные группы: (?P<имя>шаблон)
pattern := regexp.MustCompile(`(?P<name>\w+)@(?P<domain>\w+\.\w+)`)
text := "test@example.com"

// SubexpNames — получаем имена групп
groupNames := pattern.SubexpNames()
matches := pattern.FindStringSubmatch(text)

// Создаем карту: имя_группы -> значение
result := make(map[string]string)
for i, name := range groupNames {
    if i != 0 && name != "" {
        result[name] = matches[i]
    }
}
fmt.Println(result["name"])   // "test"
fmt.Println(result["domain"]) // "example.com"

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

// Замена: переставляем местами фамилию и имя
pattern := regexp.MustCompile(`(\w+) (\w+)`)
text := "Иванов Иван"

// ReplaceAllString — замена всех совпадений
// $1 — первая группа, $2 — вторая группа
result := pattern.ReplaceAllString(text, "$2 $1")
fmt.Println(result) // "Иван Иванов"

4. Продвинутые примеры и оптимизация

Валидация email

emailPattern := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)

func isValidEmail(email string) bool {
    return emailPattern.MatchString(email)
}

fmt.Println(isValidEmail("user@example.com")) // true
fmt.Println(isValidEmail("invalid-email"))    // false

Разбор URL

urlPattern := regexp.MustCompile(`^(https?)://([^/]+)(/.*)?$`)
url := "https://golang.org/pkg/regexp/"

parts := urlPattern.FindStringSubmatch(url)
if len(parts) > 0 {
    fmt.Println("Протокол:", parts[1]) // "https"
    fmt.Println("Домен:", parts[2])    // "golang.org"
    fmt.Println("Путь:", parts[3])     // "/pkg/regexp/"
}

Оптимизация производительности

// Плохо: компиляция при каждом вызове
func slowFindNumbers(text string) []string {
    pattern := regexp.MustCompile(`\d+`)
    return pattern.FindAllString(text, -1)
}

// Хорошо: компиляция один раз
var numberPattern = regexp.MustCompile(`\d+`)

func fastFindNumbers(text string) []string {
    return numberPattern.FindAllString(text, -1)
}

// Для больших объём                

Блоги

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