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

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

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

Начать курс

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

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

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

Пакет regexp реализует синтаксис регулярных выражений, совместимый с RE2 (за исключением обратных ссылок и lookahead/lookbehind). Это делает его быстрым и предсказуемым. Основные функции:

  • regexp.Compile(pattern) — компилирует шаблон в объект Regexp. Возвращает ошибку, если шаблон некорректен.
  • regexp.MustCompile(pattern) — то же самое, но вызывает панику при ошибке. Удобно для статических шаблонов.
  • MatchString(pattern, s) — проверяет, содержит ли строка s подстроку, соответствующую шаблону.

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

package main

import (
    "fmt"
    "regexp"
)

func main() {
    // Используем MustCompile для статического шаблона
    re := regexp.MustCompile(`hello`)
    match := re.MatchString("hello world")
    fmt.Println(match) // true

    // Compile для динамического шаблона
    pattern := "[0-9]+"
    re2, err := regexp.Compile(pattern)
    if err != nil {
        fmt.Println("Ошибка компиляции:", err)
        return
    }
    fmt.Println(re2.MatchString("abc123")) // true
}

Поиск и извлечение данных

Часто нужно не просто проверить совпадение, а извлечь конкретные части строки. Для этого используются методы FindString, FindStringSubmatch и FindAllString.

Извлечение первого совпадения

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\d+`)
    text := "Код: 12345, цена: 678"
    
    // Первое совпадение
    first := re.FindString(text)
    fmt.Println(first) // 12345
    
    // Все совпадения
    all := re.FindAllString(text, -1)
    fmt.Println(all) // [12345 678]
}

Извлечение групп (submatches)

Группы в шаблоне (обозначаются круглыми скобками) позволяют извлекать части совпадения. Метод FindStringSubmatch возвращает слайс, где первый элемент — полное совпадение, а последующие — значения групп.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    // Шаблон: имя пользователя @домен
    re := regexp.MustCompile(`(\w+)@(\w+\.\w+)`)
    email := "user@example.com"
    
    match := re.FindStringSubmatch(email)
    if len(match) > 0 {
        fmt.Println("Полный email:", match[0]) // user@example.com
        fmt.Println("Имя пользователя:", match[1]) // user
        fmt.Println("Домен:", match[2]) // example.com
    }
}

Метод FindAllStringSubmatch делает то же самое для всех совпадений в строке.

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

Пакет regexp предоставляет два метода для замены: ReplaceAllString (простая замена) и ReplaceAllStringFunc (замена с использованием функции).

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

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\s+`) // один или более пробелов
    text := "Hello    World   Go"
    
    result := re.ReplaceAllString(text, " ")
    fmt.Println(result) // Hello World Go
}

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

В строке замены можно ссылаться на группы с помощью $1, $2 и т.д.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    // Меняем формат даты: YYYY-MM-DD -> DD.MM.YYYY
    re := regexp.MustCompile(`(\d{4})-(\d{2})-(\d{2})`)
    date := "2025-03-30"
    
    result := re.ReplaceAllString(date, "$3.$2.$1")
    fmt.Println(result) // 30.03.2025
}

Замена с функцией

Метод ReplaceAllStringFunc позволяет динамически преобразовывать каждое совпадение.

package main

import (
    "fmt"
    "regexp"
    "strings"
)

func main() {
    re := regexp.MustCompile(`\b\w+\b`) // каждое слово
    text := "hello world go"
    
    // Преобразуем каждое слово в верхний регистр
    result := re.ReplaceAllStringFunc(text, func(s string) string {
        return strings.ToUpper(s)
    })
    fmt.Println(result) // HELLO WORLD GO
}

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

Валидация email-адреса

package main

import (
    "fmt"
    "regexp"
)

func isValidEmail(email string) bool {
    // Упрощенный, но рабочий шаблон для email
    re := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
    return re.MatchString(email)
}

func main() {
    emails := []string{"test@example.com", "invalid-email", "user@domain"}
    for _, e := range emails {
        fmt.Printf("%s - %t\n", e, isValidEmail(e))
    }
}

Извлечение URL из текста

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`https?://[^\s]+`)
    text := "Посетите сайт https://golang.org и https://github.com"
    
    urls := re.FindAllString(text, -1)
    for _, url := range urls {
        fmt.Println("Найден URL:", url)
    }
}

Разделение строки по сложному разделителю

Блоги

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