Extensions to Go's regexp package for easier handling of named capture groups.
go get github.com/jecoms/regextra@latestpackage main
import (
"fmt"
"regexp"
"github.com/jecoms/regextra"
)
func main() {
re := regexp.MustCompile(`(?P<name>\w+) (?P<age>\d+)`)
// Extract a single named group
name, ok := regextra.FindNamed(re, "Alice 30", "name")
if ok {
fmt.Println("Name:", name) // Output: Name: Alice
}
// Get all named groups as a map
groups := regextra.NamedGroups(re, "Alice 30")
fmt.Println(groups) // Output: map[age:30 name:Alice]
// Unmarshal into a struct with type conversion
type Person struct {
Name string
Age int
}
var person Person
regextra.Unmarshal(re, "Bob 25", &person)
fmt.Printf("%s is %d\n", person.Name, person.Age) // Output: Bob is 25
// Unmarshal all matches into a slice
var people []Person
regextra.UnmarshalAll(re, "Alice 30 and Bob 25", &people)
fmt.Println(len(people)) // Output: 2
}Extract a single named capture group from the target string.
Returns the matched value and true if found, or empty string and false if not found.
re := regexp.MustCompile(`(?P<price>\$\d+\.\d{2})`)
price, ok := regextra.FindNamed(re, "Total: $19.99", "price")
// price = "$19.99", ok = trueExtract all named capture groups as a map. If a group name appears multiple times, only the last match is returned.
Returns an empty map if no match is found.
re := regexp.MustCompile(`(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})`)
groups := regextra.NamedGroups(re, "Date: 2025-10-04")
// groups = map[string]string{"year": "2025", "month": "10", "day": "04"}Extract all values for each named capture group, handling duplicate group names within a single match.
Returns an empty map if no match is found.
re := regexp.MustCompile(`(?P<word>\w+) (?P<word>\w+) (?P<word>\w+)`)
allGroups := regextra.AllNamedGroups(re, "one two three")
// allGroups = map[string][]string{"word": []string{"one", "two", "three"}}Unmarshal regex matches into a struct with automatic type conversion. Similar to json.Unmarshal, but for regex patterns.
Supported field types: string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool
Field mapping priority:
- Struct tag
regex:"groupname"if provided (highest priority) - Exact field name match with capture group name
- Case-insensitive field name match
- Unexported fields are ignored
Returns an error if the target is not a pointer to a struct, or if type conversion fails.
type Person struct {
Name string
Age int
}
re := regexp.MustCompile(`(?P<name>\w+) is (?P<age>\d+)`)
var person Person
err := regextra.Unmarshal(re, "Alice is 30", &person)
// person.Name = "Alice", person.Age = 30With struct tags:
type Email struct {
Username string `regex:"user"`
Domain string `regex:"domain"`
}
re := regexp.MustCompile(`(?P<user>\w+)@(?P<domain>[\w.]+)`)
var email Email
err := regextra.Unmarshal(re, "[email protected]", &email)
// email.Username = "alice", email.Domain = "example.com"UnmarshalAll finds all occurrences of the regex pattern in the target string and unmarshals them into a slice of structs. The slice is cleared before populating.
v must be a pointer to a slice of structs. If no matches are found, the slice will be empty.
Supported field types: Same as Unmarshal
Field mapping priority: Same as Unmarshal
type Person struct {
Name string
Age int
}
re := regexp.MustCompile(`(?P<name>\w+) is (?P<age>\d+)`)
var people []Person
err := regextra.UnmarshalAll(re, "Alice is 30 and Bob is 25", &people)
// people = []Person{
// {Name: "Alice", Age: 30},
// {Name: "Bob", Age: 25},
// }The standard library's regexp package requires verbose code to extract named capture groups:
// Standard library approach (verbose)
re := regexp.MustCompile(`(?P<name>\w+) (?P<age>\d+)`)
matches := re.FindStringSubmatch("Alice 30")
if matches != nil {
nameIndex := re.SubexpIndex("name")
name := matches[nameIndex] // "Alice"
}
// regextra approach (simple)
re := regexp.MustCompile(`(?P<name>\w+) (?P<age>\d+)`)
name, ok := regextra.FindNamed(re, "Alice 30", "name") // "Alice", true- ✅ Simple functions - No wrapper types, works directly with
*regexp.Regexp - ✅ Named group extraction - Extract groups by name without index juggling
- ✅ Map-based access - Get all named groups in one call
- ✅ Struct unmarshaling - Type-safe extraction with automatic conversion
- ✅ Safe by default - Built-in nil checks, returns empty values on no match
- ✅ Zero dependencies - Only depends on Go's standard library
MIT