// Регулярные выражения: автоматный движок Go
// Запуск: go run regex_demo.go

package main

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

func main() {
	fmt.Println("=== Go: регулярные выражения ===")
	fmt.Println()

	// 1. Go regexp — автоматный движок (Thompson NFA)
	fmt.Println("--- 1. Go regexp: автоматный подход ---")
	re := regexp.MustCompile(`^a+b$`)
	tests := []string{"b", "ab", "aaab", "aaa", "", "abc"}
	for _, s := range tests {
		fmt.Printf("  %-6q → %v\n", s, re.MatchString(s))
	}
	fmt.Println()

	// 2. Линейное время даже на «злых» паттернах
	fmt.Println("--- 2. Защита от ReDoS ---")
	// Паттерн (a+)+b вызывает экспоненциальный бэктрекинг в PCRE.
	// В Go regexp — всегда линейное время.
	evil := regexp.MustCompile(`^(a+)+b$`)

	for _, n := range []int{100, 1_000, 10_000, 100_000} {
		input := strings.Repeat("a", n)
		start := time.Now()
		_ = evil.MatchString(input) // Всегда false, но O(N)
		elapsed := time.Since(start)
		fmt.Printf("  N=%7d → %v\n", n, elapsed)
	}
	fmt.Println("Время линейно. Go regexp не подвержен ReDoS.")
	fmt.Println()

	// 3. Что Go regexp НЕ поддерживает
	fmt.Println("--- 3. Ограничения ---")
	fmt.Println("Go regexp не поддерживает:")
	fmt.Println("  - backreferences (\\1, \\2)")
	fmt.Println("  - lookahead (?=...) и lookbehind (?<=...)")
	fmt.Println("  - possessive quantifiers (a++)")
	fmt.Println("  - атомарные группы (?>...)")
	fmt.Println("Все эти фичи требуют бэктрекинга.")
	fmt.Println("Цена автоматного подхода — ограниченный синтаксис.")
	fmt.Println()

	// 4. Компиляция регулярки
	fmt.Println("--- 4. Компиляция ---")
	fmt.Println("regexp.Compile() может вернуть ошибку.")
	fmt.Println("regexp.MustCompile() паникует при ошибке (для констант).")
	_, err := regexp.Compile(`[invalid`)
	if err != nil {
		fmt.Printf("Ошибка компиляции: %v\n", err)
	}
	fmt.Println()

	// 5. Именованные группы
	fmt.Println("--- 5. Именованные группы ---")
	dateRe := regexp.MustCompile(`(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})`)
	match := dateRe.FindStringSubmatch("2038-01-19")
	for i, name := range dateRe.SubexpNames() {
		if i != 0 && name != "" {
			fmt.Printf("  %s = %s\n", name, match[i])
		}
	}

	fmt.Println("\n--- Итог ---")
	fmt.Println("Go regexp = Thompson NFA = линейное время = без ReDoS")
	fmt.Println("Нет backreferences / lookaround — осознанный выбор")
	fmt.Println("Синтаксис RE2 (Google)")
}
