Learn how to find submatch indexes using regular expressions in Go. Includes examples of regex matching.
last modified April 20, 2025
This tutorial explains how to use the Regexp.FindSubmatchIndex method in Go. We’ll cover submatch indices and provide practical examples.
A regular expression is a sequence of characters that defines a search pattern. It’s used for pattern matching within strings.
The Regexp.FindSubmatchIndex method returns a slice holding the index pairs identifying the leftmost match and submatches. It’s useful for extracting matched portions and their positions.
The simplest use of FindSubmatchIndex finds matches and their positions. Here we locate a simple word and its position.
basic_indices.go
package main
import ( “fmt” “regexp” )
func main() {
re := regexp.MustCompile(hello
)
str := “hello world hello again”
indices := re.FindSubmatchIndex([]byte(str))
if indices != nil {
fmt.Println("Full match:", str[indices[0]:indices[1]])
fmt.Printf("Positions: %d to %d\n", indices[0], indices[1])
}
}
The method returns a slice where indices[0] is the start and indices[1] is the end of the match. We can use these to extract the matched substring.
This example shows how to get both the matched date components and their positions in the input string.
date_indices.go
package main
import ( “fmt” “regexp” )
func main() {
re := regexp.MustCompile((\d{4})-(\d{2})-(\d{2})
)
str := “Event date: 2025-04-20, deadline: 2025-05-15”
indices := re.FindSubmatchIndex([]byte(str))
if indices != nil {
fmt.Println("Full match:", str[indices[0]:indices[1]])
fmt.Println("Year:", str[indices[2]:indices[3]])
fmt.Println("Month:", str[indices[4]:indices[5]])
fmt.Println("Day:", str[indices[6]:indices[7]])
}
}
Each capture group gets two indices in the result slice. The pattern has three groups, so we get seven index pairs (including the full match).
To find all matches with their positions, we use FindAllSubmatchIndex. This shows all dates in a string with their locations.
all_indices.go
package main
import ( “fmt” “regexp” )
func main() {
re := regexp.MustCompile((\d{4})-(\d{2})-(\d{2})
)
str := “Dates: 2025-04-20, 2025-05-15, 2025-06-30”
allIndices := re.FindAllSubmatchIndex([]byte(str), -1)
for _, indices := range allIndices {
fmt.Printf("Found date %s at position %d\n",
str[indices[0]:indices[1]], indices[0])
}
}
The method returns a slice of index slices. Each inner slice contains the positions for one match. The second parameter limits the number of matches.
Named capture groups make the code more readable. This example shows how to work with named groups and their indices.
named_groups.go
package main
import ( “fmt” “regexp” )
func main() {
re := regexp.MustCompile((?P\d{4})-(?P\d{2})-(?P\d{2})
)
str := “Today is 2025-04-20”
indices := re.FindSubmatchIndex([]byte(str))
if indices != nil {
for i, name := range re.SubexpNames() {
if i != 0 && name != "" {
start := indices[2*i]
end := indices[2*i+1]
fmt.Printf("%s: %s\n", name, str[start:end])
}
}
}
}
Named groups are accessed via SubexpNames. The indices follow the same pattern as numbered groups but with meaningful names.
This example validates email addresses while also tracking their positions in the input text.
email_indices.go
package main
import ( “fmt” “regexp” )
func main() {
re := regexp.MustCompile(([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})
)
str := “Contact us at info@example.com or support@company.org”
allIndices := re.FindAllSubmatchIndex([]byte(str), -1)
for _, indices := range allIndices {
fmt.Printf("Found email %s at position %d\n",
str[indices[0]:indices[1]], indices[0])
fmt.Printf("Username: %s\n", str[indices[2]:indices[3]])
fmt.Printf("Domain: %s\n", str[indices[4]:indices[5]])
}
}
The pattern captures both the full email and its components. The indices help locate each part within the original string.
For complex patterns with many groups, FindSubmatchIndex helps extract specific parts while knowing their exact positions.
complex_pattern.go
package main
import ( “fmt” “regexp” )
func main() {
re := regexp.MustCompile((\w+):(\d+):(\d+\.\d+)
)
str := “item1:42:3.14,item2:99:2.72,item3:7:1.61”
allIndices := re.FindAllSubmatchIndex([]byte(str), -1)
for i, indices := range allIndices {
fmt.Printf("Match %d:\n", i+1)
fmt.Printf(" Name: %s\n", str[indices[2]:indices[3]])
fmt.Printf(" ID: %s\n", str[indices[4]:indices[5]])
fmt.Printf(" Value: %s\n", str[indices[6]:indices[7]])
}
}
The pattern matches name-value pairs with IDs. The indices let us extract each component precisely, even in a complex string.
This example extracts HTML tags and their attributes while tracking their positions in the document.
html_tags.go
package main
import ( “fmt” “regexp” )
func main() {
re := regexp.MustCompile(<([a-zA-Z]+)(\s+[^>]*)?>
)
html := `# Title
`
allIndices := re.FindAllSubmatchIndex([]byte(html), -1)
for _, indices := range allIndices {
tag := html[indices[2]:indices[3]]
fullTag := html[indices[0]:indices[1]]
fmt.Printf("Found %s tag at position %d\n", tag, indices[0])
fmt.Printf(" Full tag: %s\n", fullTag)
}
}
The pattern matches HTML tags and captures the tag name. The indices help locate each tag in the HTML string for further processing.
Go regexp package documentation
This tutorial covered the Regexp.FindSubmatchIndex method in Go with practical examples of pattern matching with position tracking.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Go tutorials.