Go Quickly - Regexp Templates
Did you know that Go supports Perl-style template expansion for regular expressions? Using this tool, you can capture a regular expression pattern and then expand it into a simple string template. Here's how it works.
package main
import (
"fmt"
"os"
"regexp"
)
func main() {
dst := make([]byte, 0, 1024)
source := `"matt"`
re := regexp.MustCompile(`"(?P<name>[a-z]+)"`)
tpl := "My name is ${name}."
matches := re.FindStringSubmatchIndex(source)
out := re.ExpandString(dst, tpl, source, matches)
fmt.Fprintf(os.Stdout, "%s\n", out)
}
The big feature we are interested in here is regexp.Regexp.ExpandString()
. This function takes a group of matches from a regular expression and expands them into a template string. (There's a []byte
equivalent called regexp.Regexp.Expand()
)
In the example above, dst
is the destination byte slice. source
is the source text that we'll evaluate for matches. re
is our compiled regular expression. We'll return to this in just a moment. Finally, tpl
is our template.
The process for expanding a template goes like this:
- Get a regular expression
- Run the relevant
SubmatchIndex
function on your source text - Expand the results into your template.
For regular expressions, a template follows a very simple syntax:
$1
(or$
plus any digit) is evaluated as a location variable. That is,$1
is the match in index 1.${foo}
(or${string}
) looks for a named subpattern and substitutes it. That is${foo}
matches a pattern named with(?P<foo>)
inside of the regular expression.$$
is the literal$
.
The curly braces are actually optional, but I find it less error-prone to use them.
So when we combine our regular expression and our template, we get this:
"(?P<name>[a-z]+)"
finds an a-z string and stores it with a name${name}
."My name is ${name}."
substitutes the matched name into the${name}
placeholder.
So the output of the above program is:
⇒ go run expand.go
My name is matt.
And that's how to Go quickly with regular expression template expansion.