Golang Regex: regexp Package Best Practices
Learn Go language's regexp package, master efficient regex usage techniques and best practices.
Go language's regexp package provides powerful and efficient regex functionality. This guide will take you from basics to advanced, covering everything you need to know about regex in Go.
Go regexp Package Basics
Import Package
import "regexp"
Core Concepts
Go's regexp package mainly contains two core structures:
- Regexp: A compiled regular expression object
- Match: Match-related functions and results
Basic Usage
1. Simple Matching
Using Compile and MustCompile
package main
import (
"fmt"
"regexp"
)
func main() {
// Compile regex (may return error)
pattern, err := regexp.Compile("\\d+")
if err != nil {
panic(err)
}
// Or use MustCompile (panics on error)
pattern := regexp.MustCompile("\\d+")
// Check if it matches
matched := pattern.MatchString("Hello 123 World")
fmt.Println(matched) // true
}
Using MatchString and Match
// MatchString - Match string
matched := regexp.MustCompile("hello").MatchString("hello world")
fmt.Println(matched) // true
// Match - Match byte slice
matched = regexp.MustCompile("hello").Match([]byte("hello world"))
fmt.Println(matched) // true
2. Finding Matches
FindString - Find First Match
pattern := regexp.MustCompile("\\d+")
text := "abc123def456"
result := pattern.FindString(text)
fmt.Println(result) // "123"
FindAllString - Find All Matches
pattern := regexp.MustCompile("\\d+")
text := "abc123def456ghi789"
results := pattern.FindAllString(text, -1)
fmt.Println(results) // ["123", "456", "789"]
// Limit match count
results = pattern.FindAllString(text, 2)
fmt.Println(results) // ["123", "456"]
FindStringIndex - Get Position Info
pattern := regexp.MustCompile("\\d+")
text := "abc123def"
result := pattern.FindStringIndex(text)
fmt.Println(result) // [3, 6] // Start and end positions
// Get match content and position
matchedText := text[result[0]:result[1]]
fmt.Println(matchedText) // "123"
FindAllStringIndex - Get All Positions
pattern := regexp.MustCompile("\\d+")
text := "abc123def456"
results := pattern.FindAllStringIndex(text, -1)
fmt.Println(results) // [[3 6] [9 12]]
Advanced Features
1. Group Capturing
FindStringSubmatch - Get Capture Groups
pattern := regexp.MustCompile("(\\d{4})-(\\d{2})-(\\d{2})")
text := "Date: 2024-01-25"
result := pattern.FindStringSubmatch(text)
fmt.Println(result[0]) // "2024-01-25" - Full match
fmt.Println(result[1]) // "2024" - First capture group
fmt.Println(result[2]) // "01" - Second capture group
fmt.Println(result[3]) // "25" - Third capture group
FindAllStringSubmatch - Get All Capture Groups
pattern := regexp.MustCompile("(\\d{2})-(\\d{2})-(\\d{4})")
text := "Born: 25-01-1990, Graduated: 15-06-2012"
results := pattern.FindAllStringSubmatch(text, -1)
for _, match := range results {
fmt.Printf("Full: %s, Day: %s, Month: %s, Year: %s\n",
match[0], match[1], match[2], match[3])
}
// Output:
// Full: 25-01-1990, Day: 25, Month: 01, Year: 1990
// Full: 15-06-2012, Day: 15, Month: 06, Year: 2012
2. Replacement Operations
ReplaceAllString - Replace All Matches
pattern := regexp.MustCompile("\\d+")
text := "Price: 100, 200, 300"
result := pattern.ReplaceAllString(text, "[number]")
fmt.Println(result) // "Price: [number], [number], [number]"
ReplaceAllStringFunc - Replace with Function
package main
import (
"fmt"
"regexp"
"strconv"
)
func main() {
pattern := regexp.MustCompile("\\d+")
text := "Price: 100, 200, 300"
result := pattern.ReplaceAllStringFunc(text, func(match string) string {
num, _ := strconv.Atoi(match)
return fmt.Sprintf("%.1f", float64(num)*0.9)
})
fmt.Println(result) // "Price: 90.0, 180.0, 270.0"
}
ReplaceAllLiteralString - Literal Replacement
pattern := regexp.MustCompile("\\$(\\w+)")
text := "Price: $100, $200"
result := pattern.ReplaceAllLiteralString(text, "[$1]")
fmt.Println(result) // "Price: [$1], [$1]" // Doesn't interpret $1
// Compare with ReplaceAllString
result2 := pattern.ReplaceAllString(text, "[$1]")
fmt.Println(result2) // "Price: [$100], [$200]" // Interprets $1
3. Splitting Operations
Split - Split String
pattern := regexp.MustCompile("[,;|]")
text := "apple,banana;orange|grape"
result := pattern.Split(text, -1)
fmt.Println(result) // ["apple", "banana", "orange", "grape"]
// Limit split count
result = pattern.Split(text, 2)
fmt.Println(result) // ["apple", "banana;orange|grape"]
4. Named Capture Groups
pattern := regexp.MustCompile("(?P<year>\\d{4})-(?P<month>\\d{2})-(?P<day>\\d{2})")
text := "2024-01-25"
match := pattern.FindStringSubmatch(text)
if match != nil {
// Access by index
fmt.Println(match[1]) // "2024"
// Access by name
fmt.Println(pattern.SubexpNames()) // ["", "year", "month", "day"]
names := pattern.SubexpNames()
result := make(map[string]string)
for i, name := range names {
if i != 0 && name != "" {
result[name] = match[i]
}
}
fmt.Println(result["year"]) // "2024"
fmt.Println(result["month"]) // "01"
fmt.Println(result["day"]) // "25"
}
Practical Examples
Example 1: Validate Email Address
package main
import (
"fmt"
"regexp"
)
func isValidEmail(email string) bool {
pattern := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
return pattern.MatchString(email)
}
func main() {
fmt.Println(isValidEmail("[email protected]")) // true
fmt.Println(isValidEmail("invalid.email")) // false
fmt.Println(isValidEmail("user@domain")) // false
}
Example 2: Extract All Emails
package main
import (
"fmt"
"regexp"
)
func extractEmails(text string) []string {
pattern := regexp.MustCompile(`[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`)
return pattern.FindAllString(text, -1)
}
func main() {
text := "Contact: [email protected], [email protected], [email protected]"
emails := extractEmails(text)
fmt.Println(emails)
// Output: [[email protected] [email protected] [email protected]]
}
Example 3: Extract URL Parameters
package main
import (
"fmt"
"regexp"
)
func extractURLParams(url string) map[string]string {
pattern := regexp.MustCompile(`[?&]([^=]+)=([^&]+)`)
matches := pattern.FindAllStringSubmatch(url, -1)
params := make(map[string]string)
for _, match := range matches {
params[match[1]] = match[2]
}
return params
}
func main() {
url := "https://example.com?name=John&age=30&city=NYC"
params := extractURLParams(url)
fmt.Printf("%+v\n", params)
// Output: map[age:30 city:NYC name:John]
}
Example 4: Validate Phone Number
package main
import (
"fmt"
"regexp"
)
func isValidPhone(phone string) bool {
pattern := regexp.MustCompile(`^1[3-9]\d{9}$`)
return pattern.MatchString(phone)
}
func main() {
fmt.Println(isValidPhone("13812345678")) // true
fmt.Println(isValidPhone("12345678901")) // false
fmt.Println(isValidPhone("1381234567")) // false
}
Example 5: Extract IP Addresses
package main
import (
"fmt"
"regexp"
)
func extractIPAddresses(text string) []string {
// IPv4
ipv4Pattern := regexp.MustCompile(`\b(?:\d{1,3}\.){3}\d{1,3}\b`)
return ipv4Pattern.FindAllString(text, -1)
}
func main() {
text := "Server: 192.168.1.1, Backup: 10.0.0.1, External: 8.8.8.8"
ips := extractIPAddresses(text)
fmt.Println(ips)
// Output: [192.168.1.1 10.0.0.1 8.8.8.8]
}
Example 6: Password Strength Validation
package main
import (
"fmt"
"regexp"
)
func validatePassword(password string) (bool, string) {
if len(password) < 8 {
return false, "Password must be at least 8 characters"
}
if !regexp.MustCompile(`[A-Z]`).MatchString(password) {
return false, "Password must contain uppercase letters"
}
if !regexp.MustCompile(`[a-z]`).MatchString(password) {
return false, "Password must contain lowercase letters"
}
if !regexp.MustCompile(`\d`).MatchString(password) {
return false, "Password must contain numbers"
}
if !regexp.MustCompile(`[!@#$%^&*]`).MatchString(password) {
return false, "Password must contain special characters"
}
return true, "Password meets requirements"
}
func main() {
password := "MyPass123!"
valid, message := validatePassword(password)
fmt.Println(valid, message)
}
Example 7: HTML Tag Cleanup
package main
import (
"fmt"
"regexp"
)
func stripHTML(html string) string {
pattern := regexp.MustCompile("<[^>]+>")
return pattern.ReplaceAllString(html, "")
}
func main() {
html := "<p>Hello <b>World</b>!</p>"
clean := stripHTML(html)
fmt.Println(clean) // "Hello World!"
}
Example 8: Log Parsing
package main
import (
"fmt"
"regexp"
)
type LogEntry struct {
Date string
Time string
Level string
Message string
}
func parseLog(log string) *LogEntry {
pattern := regexp.MustCompile(`(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)`)
match := pattern.FindStringSubmatch(log)
if match == nil {
return nil
}
return &LogEntry{
Date: match[1],
Time: match[2],
Level: match[3],
Message: match[4],
}
}
func main() {
log := "2024-01-25 10:30:45 [INFO] User login successful"
entry := parseLog(log)
if entry != nil {
fmt.Printf("Time: %s %s\n", entry.Date, entry.Time)
fmt.Printf("Level: %s\n", entry.Level)
fmt.Printf("Message: %s\n", entry.Message)
}
}
Best Practices
1. Pre-compile Regular Expressions
// Good practice: Pre-compile
var emailPattern = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
func isValidEmail(email string) bool {
return emailPattern.MatchString(email)
}
// Bad practice: Compile every time
func isValidEmailBad(email string) bool {
pattern := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
return pattern.MatchString(email)
}
2. Use Raw Strings
// Good practice: Use backticks
pattern := regexp.MustCompile(`\d+`)
// Bad practice: Need escaping
pattern := regexp.MustCompile("\\d+")
3. Error Handling
// Good practice: Handle compilation errors
pattern, err := regexp.Compile("[" + userInput + "]")
if err != nil {
log.Fatalf("Invalid regex: %v", err)
}
// Specific scenario uses MustCompile
var pattern = regexp.MustCompile(`\d+`) // Compile-time determined to be error-free
4. Use Package-level Variables
package utils
import "regexp"
var (
EmailPattern = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
PhonePattern = regexp.MustCompile(`^1[3-9]\d{9}$`)
DatePattern = regexp.MustCompile(`^(\d{4})-(\d{2})-(\d{2})$`)
)
5. Avoid Greedy Matching
// Good practice: Non-greedy
pattern := regexp.MustCompile(`<div>.*?</div>`)
// Bad practice: Greedy
pattern := regexp.MustCompile(`<div>.*</div>`)
Performance Optimization
1. Reuse Compiled Patterns
// Efficient
var pattern = regexp.MustCompile(`\d+`)
func processTexts(texts []string) {
for _, text := range texts {
pattern.FindAllString(text, -1)
}
}
2. Use More Specific Patterns
// Efficient
pattern := regexp.MustCompile(`\d{3}-\d{4}-\d{4}`)
// Inefficient
pattern := regexp.MustCompile(`.+`)
3. Limit Match Count
// Limit result count, avoid wasting memory
pattern := regexp.MustCompile(`\d+`)
results := pattern.FindAllString(text, 10) // At most 10
Common Pitfalls
1. Forgetting to Pre-compile
// Bad practice: Compile every loop iteration
for _, text := range texts {
pattern := regexp.MustCompile(`\d+`)
pattern.FindAllString(text, -1)
}
// Good practice: Compile once
pattern := regexp.MustCompile(`\d+`)
for _, text := range texts {
pattern.FindAllString(text, -1)
}
2. Incorrect Backslash Usage
// Bad practice: Using double quotes requires escaping
pattern := regexp.MustCompile("\\d+")
// Good practice: Using backticks
pattern := regexp.MustCompile(`\d+`)
3. Ignoring Error Handling
// Bad practice: Ignore errors
pattern, _ := regexp.Compile(userInput)
// Good practice: Handle errors
pattern, err := regexp.Compile(userInput)
if err != nil {
return fmt.Errorf("Invalid regex: %w", err)
}
4. Not Checking Match Results
// Bad practice: Might be nil
match := pattern.FindStringSubmatch(text)
fmt.Println(match[1]) // Might panic
// Good practice: Check for nil
match := pattern.FindStringSubmatch(text)
if match != nil {
fmt.Println(match[1])
}
Summary
Go's regexp package provides powerful and efficient regex functionality:
- Compile:
Compile()andMustCompile() - Match:
MatchString()andMatch() - Find:
FindString(),FindAllString() - Groups:
FindStringSubmatch(),FindAllStringSubmatch() - Replace:
ReplaceAllString(),ReplaceAllStringFunc() - Split:
Split()
Best practices:
- Pre-compile regular expressions
- Use raw strings (backticks)
- Handle errors properly
- Reuse compiled patterns
- Use non-greedy matching
Master these techniques, and you can efficiently handle various text processing tasks in Go!
Use our online Regex Tester to test Go regex patterns!
About the Author
The Regex Master Team consists of experienced developers and technical writers dedicated to simplifying regular expressions for everyone. We ensure all patterns are rigorously tested and verified to provide accurate, production-ready solutions.
Try It: Regex Tester
Use our interactive regex tester to experiment with the patterns you learned in this article. Test your regular expressions in real-time and see immediate results.