Регулярные выражения в 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)
}
}