Регулярные выражения в Go: полный разбор с примерами

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

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

Начать курс

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

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

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

Пакет regexp предоставляет два основных способа компиляции регулярного выражения:

  • regexp.Compile(pattern string) (*Regexp, error) — компилирует шаблон и возвращает объект Regexp или ошибку, если шаблон некорректен.
  • regexp.MustCompile(pattern string) *Regexp — то же самое, но вызывает panic при ошибке. Удобно для статических шаблонов, определённых на этапе инициализации.

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

Пример 1: Поиск подстроки (FindString)

Функция FindString возвращает первое совпадение с шаблоном в виде строки. Если совпадений нет — возвращает пустую строку.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    text := "Мой email: example@mail.com, запасной: test@example.org"
    pattern := `[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`

    re := regexp.MustCompile(pattern)
    match := re.FindString(text)

    fmt.Println("Найден email:", match) // Вывод: example@mail.com
}

Пример 2: Поиск всех совпадений (FindAllString)

Если нужно найти все совпадения, используйте FindAllString. Второй аргумент — максимальное количество совпадений (-1 — все).

package main

import (
    "fmt"
    "regexp"
)

func main() {
    text := "Коды: ABC-123, XYZ-456, QWE-789"
    pattern := `[A-Z]{3}-\d{3}`

    re := regexp.MustCompile(pattern)
    matches := re.FindAllString(text, -1)

    fmt.Println("Найденные коды:", matches)
    // Вывод: [ABC-123 XYZ-456 QWE-789]
}

Пример 3: Замена текста (ReplaceAllString)

ReplaceAllString заменяет все совпадения шаблона на указанную строку. Можно использовать группы захвата с синтаксисом $1, $2 и т.д.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    text := "Дата: 2024-01-15, ещё дата: 2023-12-31"
    pattern := `(\d{4})-(\d{2})-(\d{2})`

    re := regexp.MustCompile(pattern)
    // Меняем формат с ГГГГ-ММ-ДД на ДД.ММ.ГГГГ
    result := re.ReplaceAllString(text, "$3.$2.$1")

    fmt.Println("Результат:", result)
    // Вывод: Дата: 15.01.2024, ещё дата: 31.12.2023
}

Пример 4: Проверка соответствия строки шаблону (MatchString)

Функция MatchString возвращает true, если в строке есть хотя бы одно совпадение с шаблоном.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    emails := []string{"user@example.com", "invalid-email", "admin@site.org"}
    pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`

    re := regexp.MustCompile(pattern)
    for _, email := range emails {
        if re.MatchString(email) {
            fmt.Printf("'%s' — корректный email\n", email)
        } else {
            fmt.Printf("'%s' — НЕ корректный email\n", email)
        }
    }
    // Вывод:
    // 'user@example.com' — корректный email
    // 'invalid-email' — НЕ корректный email
    // 'admin@site.org' — корректный email
}

Пример 5: Извлечение данных с помощью групп захвата (FindStringSubmatch)

FindStringSubmatch возвращает срез строк, где первый элемент — полное совпадение, а остальные — содержимое групп захвата.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    text := "IP адрес: 192.168.1.1, порт: 8080"
    pattern := `(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})`

    re := regexp.MustCompile(pattern)
    matches := re.FindStringSubmatch(text)

    fmt.Println("Полное совпадение:", matches[0]) // 192.168.1.1
    fmt.Println("Октеты:", matches[1:])           // [192 168 1 1]
}

Пример 6: Замена с использованием функции (ReplaceAllStringFunc)

Если вам нужно динамически формировать замену на основе найденного совпадения, используйте ReplaceAllStringFunc. Второй аргумент — функция, которая принимает строку совпадения и возвращает строку замены.

package main

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

func main() {
    text := "Привет, мир! Как дела?"
    pattern := `[А-Яа-я]+`

    re := regexp.MustCompile(pattern)
    result := re.ReplaceAllStringFunc(text, func(match string) string {
        return strings.ToUpper(match)
    })

    fmt.Println("Результат:", result)
    // Вывод: ПРИВЕТ, МИР! КАК ДЕЛА?
}

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

  • Компилируйте один раз. Если вы используете один и тот же шаблон многократно, компилируйте его один раз (например, в глобальной переменной или в структуре) и переиспользуйте объект *Regexp.
  • Избегайте избыточных шаблонов. Чем сложнее шаблон, тем медленнее выполняется поиск. Для простых задач (например, поиск подстроки) используйте функции из

Блоги

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