Working with Regular Expressions in Go
Go's regexp
package provides comprehensive support for regular expressions. This guide covers pattern matching, text processing, and common regex patterns.
Basic Regular Expressions
Creating Regex Patterns
func regexBasics() error {
// Compile regex pattern
pattern := `^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`
re, err := regexp.Compile(pattern)
if err != nil {
return fmt.Errorf("compiling regex: %w", err)
}
// MustCompile panics on error
emailRe := regexp.MustCompile(pattern)
// Case-insensitive compilation
caseInsensitive := regexp.MustCompile(`(?i)hello`)
return nil
}
Pattern Matching
func matchExamples() {
re := regexp.MustCompile(`\d{3}-\d{2}-\d{4}`)
// Test if string matches pattern
matches := re.MatchString("123-45-6789")
// Find first match
match := re.FindString("SSN: 123-45-6789")
// Find all matches
allMatches := re.FindAllString("SSN1: 123-45-6789, SSN2: 987-65-4321", -1)
// Find match locations
loc := re.FindStringIndex("SSN: 123-45-6789")
if loc != nil {
start, end := loc[0], loc[1]
fmt.Printf("Match from %d to %d\n", start, end)
}
}
Advanced Features
Capturing Groups
func groupExamples() {
re := regexp.MustCompile(`(\w+):(\d+)`)
// Find submatch
match := re.FindStringSubmatch("port:8080")
if len(match) > 0 {
full := match[0] // "port:8080"
key := match[1] // "port"
value := match[2] // "8080"
}
// Find all submatches
text := "port:8080 host:localhost"
allMatches := re.FindAllStringSubmatch(text, -1)
for _, match := range allMatches {
fmt.Printf("Key: %s, Value: %s\n", match[1], match[2])
}
}
Named Groups
func namedGroups() {
re := regexp.MustCompile(`(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})`)
match := re.FindStringSubmatch("2024-03-19")
if len(match) > 0 {
// Get group names
names := re.SubexpNames()
// Create map of named groups
result := make(map[string]string)
for i, name := range names {
if i != 0 && name != "" {
result[name] = match[i]
}
}
fmt.Printf("Year: %s, Month: %s, Day: %s\n",
result["year"], result["month"], result["day"])
}
}
String Manipulation
Replacement
func replaceExamples() {
re := regexp.MustCompile(`\b\w+@\w+\.\w+\b`)
// Replace first match
result := re.ReplaceString(
"Contact: [email protected]",
"[EMAIL REDACTED]",
)
// Replace all matches
result = re.ReplaceAllString(
"Email1: [email protected], Email2: [email protected]",
"[EMAIL REDACTED]",
)
// Replace with function
result = re.ReplaceAllStringFunc(
"[email protected] [email protected]",
func(s string) string {
return strings.Repeat("*", len(s))
},
)
}
Splitting
func splitExamples() {
re := regexp.MustCompile(`[,\s]+`)
// Split string
parts := re.Split("apple,orange banana grape", -1)
// ["apple", "orange", "banana", "grape"]
// Split with limit
parts = re.Split("apple,orange banana grape", 2)
// ["apple", "orange banana grape"]
}
Common Patterns
Validation Patterns
var (
emailPattern = `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`
phonePattern = `^\+?1?\d{9,15}$`
usernamePattern = `^[a-zA-Z0-9_]{3,20}$`
passwordPattern = `^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$`
urlPattern = `^https?://[\w\-]+(\.[\w\-]+)+[/#?]?.*$`
)
func validatePatterns() {
validators := map[string]*regexp.Regexp{
"email": regexp.MustCompile(emailPattern),
"phone": regexp.MustCompile(phonePattern),
"username": regexp.MustCompile(usernamePattern),
"password": regexp.MustCompile(passwordPattern),
"url": regexp.MustCompile(urlPattern),
}
// Validate input
input := map[string]string{
"email": "[email protected]",
"phone": "+1234567890",
"username": "john_doe",
"password": "Password123",
"url": "https://example.com",
}
for field, value := range input {
if !validators[field].MatchString(value) {
fmt.Printf("Invalid %s: %s\n", field, value)
}
}
}
Performance Tips
Compile Once, Use Many Times
var (
// Compile patterns at init
emailRe = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
)
func validateEmail(email string) bool {
return emailRe.MatchString(email)
}
Optimize Patterns
// Good - Anchored pattern
goodRe := regexp.MustCompile(`^prefix`)
// Bad - Unanchored pattern
badRe := regexp.MustCompile(`prefix`)
// Good - Non-capturing group
goodRe = regexp.MustCompile(`(?:prefix)`)
// Bad - Capturing group when not needed
badRe = regexp.MustCompile(`(prefix)`)
Best Practices
Error Handling
func compilePattern(pattern string) (*regexp.Regexp, error) { re, err := regexp.Compile(pattern) if err != nil { return nil, fmt.Errorf("invalid pattern %q: %w", pattern, err) } return re, nil }
Input Validation
func validateInput(input string, maxLen int) error { if len(input) > maxLen { return fmt.Errorf("input too long: max %d chars", maxLen) } return nil }
Pattern Documentation
// UserPattern matches usernames: // - Must start with a letter // - Can contain letters, numbers, and underscores // - Length between 3 and 20 characters const UserPattern = `^[a-zA-Z][a-zA-Z0-9_]{2,19}$`
Next Steps
- Learn about HTTP Client
- Explore HTTP Server
- Study Template Engine