summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2018-11-26 21:19:35 -0500
committerDave Henderson <dhenderson@gmail.com>2018-11-27 21:27:43 -0500
commit5246e7bdca52a0ccc5bc6dc8d4f1cd932c461135 (patch)
tree069c220860c69764dffc91b622b0c6fda04ac2a3
parente4cbe992bfcc8598bbd1dc388a5cc6b213b98efa (diff)
Adding more regexp functions
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
-rw-r--r--docs-src/content/functions/regexp.yml158
-rw-r--r--docs/content/functions/regexp.md205
-rw-r--r--funcs/regexp.go65
-rw-r--r--funcs/regexp_test.go97
-rw-r--r--regexp/regexp.go44
-rw-r--r--regexp/regexp_test.go98
6 files changed, 630 insertions, 37 deletions
diff --git a/docs-src/content/functions/regexp.yml b/docs-src/content/functions/regexp.yml
new file mode 100644
index 00000000..db46f797
--- /dev/null
+++ b/docs-src/content/functions/regexp.yml
@@ -0,0 +1,158 @@
+ns: regexp
+preamble: |
+ These functions allow user you to search and modify text with regular expressions.
+
+ The syntax of the regular expressions accepted is [Go's `regexp` syntax](https://golang.org/pkg/regexp/syntax/#hdr-Syntax),
+ and is the same general syntax used by Perl, Python, and other languages.
+funcs:
+ - name: regexp.Find
+ description: |
+ Returns a string holding the text of the leftmost match in `input`
+ of the regular expression `expression`.
+
+ This function provides the same behaviour as Go's
+ [`regexp.FindString`](https://golang.org/pkg/regexp/#Regexp.FindString) function.
+ pipeline: true
+ arguments:
+ - name: expression
+ required: true
+ description: The regular expression
+ - name: input
+ required: true
+ description: The input to search
+ examples:
+ - |
+ $ gomplate -i '{{ regexp.Find "[a-z]{3}" "foobar"}}'
+ foo
+ - |
+ $ gomplate -i 'no {{ "will not match" | regexp.Find "[0-9]" }}numbers'
+ no numbers
+ - name: regexp.FindAll
+ description: |
+ Returns a list of all successive matches of the regular expression.
+
+ This can be called with 2 or 3 arguments. When called with 2 arguments, the
+ `n` argument (number of matches) will be set to `-1`, causing all matches
+ to be returned.
+
+ This function provides the same behaviour as Go's
+ [`regexp.FindAllString`](https://golang.org/pkg/regexp/#Regexp.FindAllString) function.
+ pipeline: true
+ arguments:
+ - name: expression
+ required: true
+ description: The regular expression
+ - name: n
+ required: false
+ description: The number of matches to return
+ - name: input
+ required: true
+ description: The input to search
+ examples:
+ - |
+ $ gomplate -i '{{ regexp.FindAll "[a-z]{3}" "foobar" | toJSON}}'
+ ["foo", "bar"]
+ - |
+ $ gomplate -i '{{ "foo bar baz qux" | regexp.FindAll "[a-z]{3}" 3 | toJSON}}'
+ ["foo", "bar", "baz"]
+ - name: regexp.Match
+ description: |
+ Returns `true` if a given regular expression matches a given input.
+
+ This returns a boolean which can be used in an `if` condition, for example.
+ pipeline: true
+ arguments:
+ - name: expression
+ required: true
+ description: The regular expression
+ - name: input
+ required: true
+ description: The input to test
+ examples:
+ - |
+ $ gomplate -i '{{ if (.Env.USER | regexp.Match `^h`) }}username ({{.Env.USER}}) starts with h!{{end}}'
+ username (hairyhenderson) starts with h!
+ - name: regexp.Replace
+ description: |
+ Replaces matches of a regular expression with the replacement string.
+
+ The replacement is substituted after expanding variables beginning with `$`.
+
+ This function provides the same behaviour as Go's
+ [`regexp.ReplaceAllString`](https://golang.org/pkg/regexp/#Regexp.ReplaceAllString) function.
+ pipeline: true
+ arguments:
+ - name: expression
+ required: true
+ description: The regular expression string
+ - name: replacement
+ required: true
+ description: The replacement string
+ - name: input
+ required: true
+ description: The input string to operate on
+ examples:
+ - |
+ $ gomplate -i '{{ regexp.Replace "(foo)bar" "$1" "foobar"}}'
+ foo
+ - |
+ $ gomplate -i '{{ regexp.Replace "(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)" "${last}, ${first}" "Alan Turing"}}'
+ Turing, Alan
+ - name: regexp.ReplaceLiteral
+ description: |
+ Replaces matches of a regular expression with the replacement string.
+
+ The replacement is substituted directly, without expanding variables
+ beginning with `$`.
+
+ This function provides the same behaviour as Go's
+ [`regexp.ReplaceAllLiteralString`](https://golang.org/pkg/regexp/#Regexp.ReplaceAllLiteralString) function.
+ pipeline: true
+ arguments:
+ - name: expression
+ required: true
+ description: The regular expression string
+ - name: replacement
+ required: true
+ description: The replacement string
+ - name: input
+ required: true
+ description: The input string to operate on
+ examples:
+ - |
+ $ gomplate -i '{{ regexp.ReplaceLiteral "(foo)bar" "$1" "foobar"}}'
+ $1
+ - |
+ $ gomplate -i '{{ `foo.bar,baz` | regexp.ReplaceLiteral `\W` `$` }}'
+ foo$bar$baz
+ - name: regexp.Split
+ description: |
+ Splits `input` into sub-strings, separated by the expression.
+
+ This can be called with 2 or 3 arguments. When called with 2 arguments, the
+ `n` argument (number of matches) will be set to `-1`, causing all sub-strings
+ to be returned.
+
+ This is equivalent to [`strings.SplitN`](../strings/#strings-splitn),
+ except that regular expressions are supported.
+
+ This function provides the same behaviour as Go's
+ [`regexp.Split`](https://golang.org/pkg/regexp/#Regexp.Split) function.
+ pipeline: true
+ arguments:
+ - name: expression
+ required: true
+ description: The regular expression
+ - name: n
+ required: false
+ description: The number of matches to return
+ - name: input
+ required: true
+ description: The input to search
+ examples:
+ - |
+ $ gomplate -i '{{ regexp.Split `[\s,.]` "foo bar,baz.qux" | toJSON}}'
+ ["foo","bar","baz","qux"]
+ - |
+ $ gomplate -i '{{ "foo bar.baz,qux" | regexp.Split `[\s,.]` 3 | toJSON}}'
+ ["foo","bar","baz"]
diff --git a/docs/content/functions/regexp.md b/docs/content/functions/regexp.md
index c97a81a8..f7622438 100644
--- a/docs/content/functions/regexp.md
+++ b/docs/content/functions/regexp.md
@@ -5,62 +5,106 @@ menu:
parent: functions
---
-## `regexp.Replace`
+These functions allow user you to search and modify text with regular expressions.
-Replaces matches of a regular expression with the replacement string. The syntax
-of the regular expressions accepted is [Go's `regexp` syntax](https://golang.org/pkg/regexp/syntax/#hdr-Syntax),
+The syntax of the regular expressions accepted is [Go's `regexp` syntax](https://golang.org/pkg/regexp/syntax/#hdr-Syntax),
and is the same general syntax used by Perl, Python, and other languages.
-### Usage
+## `regexp.Find`
+
+Returns a string holding the text of the leftmost match in `input`
+of the regular expression `expression`.
+
+This function provides the same behaviour as Go's
+[`regexp.FindString`](https://golang.org/pkg/regexp/#Regexp.FindString) function.
+### Usage
```go
-regexp.Replace expression replacement input
+regexp.Find expression input
```
+
```go
-input | regexp.Replace expression replacement
+input | regexp.Find expression
```
### Arguments
-| name | description |
-|--------|-------|
-| `expression` | The regular expression string |
-| `replacement` | The replacement string |
-| `input` | the input string to operate on |
+| name | description |
+|------|-------------|
+| `expression` | _(required)_ The regular expression |
+| `input` | _(required)_ The input to search |
### Examples
```console
-$ gomplate -i '{{ regexp.Replace "(foo)bar" "$1" "foobar"}}'
+$ gomplate -i '{{ regexp.Find "[a-z]{3}" "foobar"}}'
foo
```
+```console
+$ gomplate -i 'no {{ "will not match" | regexp.Find "[0-9]" }}numbers'
+no numbers
+```
+
+## `regexp.FindAll`
+
+Returns a list of all successive matches of the regular expression.
+
+This can be called with 2 or 3 arguments. When called with 2 arguments, the
+`n` argument (number of matches) will be set to `-1`, causing all matches
+to be returned.
+
+This function provides the same behaviour as Go's
+[`regexp.FindAllString`](https://golang.org/pkg/regexp/#Regexp.FindAllString) function.
+
+### Usage
+```go
+regexp.FindAll expression [false] input
+```
+
+```go
+input | regexp.FindAll expression [false]
+```
+
+### Arguments
+
+| name | description |
+|------|-------------|
+| `expression` | _(required)_ The regular expression |
+| `false` | _(optional)_ The number of matches to return |
+| `input` | _(required)_ The input to search |
+
+### Examples
```console
-$ gomplate -i '{{ regexp.Replace "(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)" "${last}, ${first}" "Alan Turing"}}'
-Turing, Alan
+$ gomplate -i '{{ regexp.FindAll "[a-z]{3}" "foobar" | toJSON}}'
+["foo", "bar"]
+```
+```console
+$ gomplate -i '{{ "foo bar baz qux" | regexp.FindAll "[a-z]{3}" 3 | toJSON}}'
+["foo", "bar", "baz"]
```
## `regexp.Match`
-Returns `true` if a given regular expression matches a given input string.
+Returns `true` if a given regular expression matches a given input.
This returns a boolean which can be used in an `if` condition, for example.
### Usage
-
```go
-regexp.Match expression input
+regexp.Match expression input
```
+
```go
-input | regexp.Match expression
+input | regexp.Match expression
```
### Arguments
-| name | description |
-|--------|-------|
-| `expression` | the regular expression to match |
-| `input` | the input string to test |
+| name | description |
+|------|-------------|
+| `expression` | _(required)_ The regular expression |
+| `input` | _(required)_ The input to test |
### Examples
@@ -68,3 +112,120 @@ input | regexp.Match expression
$ gomplate -i '{{ if (.Env.USER | regexp.Match `^h`) }}username ({{.Env.USER}}) starts with h!{{end}}'
username (hairyhenderson) starts with h!
```
+
+## `regexp.Replace`
+
+Replaces matches of a regular expression with the replacement string.
+
+The replacement is substituted after expanding variables beginning with `$`.
+
+This function provides the same behaviour as Go's
+[`regexp.ReplaceAllString`](https://golang.org/pkg/regexp/#Regexp.ReplaceAllString) function.
+
+### Usage
+```go
+regexp.Replace expression replacement input
+```
+
+```go
+input | regexp.Replace expression replacement
+```
+
+### Arguments
+
+| name | description |
+|------|-------------|
+| `expression` | _(required)_ The regular expression string |
+| `replacement` | _(required)_ The replacement string |
+| `input` | _(required)_ The input string to operate on |
+
+### Examples
+
+```console
+$ gomplate -i '{{ regexp.Replace "(foo)bar" "$1" "foobar"}}'
+foo
+```
+```console
+$ gomplate -i '{{ regexp.Replace "(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)" "${last}, ${first}" "Alan Turing"}}'
+Turing, Alan
+```
+
+## `regexp.ReplaceLiteral`
+
+Replaces matches of a regular expression with the replacement string.
+
+The replacement is substituted directly, without expanding variables
+beginning with `$`.
+
+This function provides the same behaviour as Go's
+[`regexp.ReplaceAllLiteralString`](https://golang.org/pkg/regexp/#Regexp.ReplaceAllLiteralString) function.
+
+### Usage
+```go
+regexp.ReplaceLiteral expression replacement input
+```
+
+```go
+input | regexp.ReplaceLiteral expression replacement
+```
+
+### Arguments
+
+| name | description |
+|------|-------------|
+| `expression` | _(required)_ The regular expression string |
+| `replacement` | _(required)_ The replacement string |
+| `input` | _(required)_ The input string to operate on |
+
+### Examples
+
+```console
+$ gomplate -i '{{ regexp.ReplaceLiteral "(foo)bar" "$1" "foobar"}}'
+$1
+```
+```console
+$ gomplate -i '{{ `foo.bar,baz` | regexp.ReplaceLiteral `\W` `$` }}'
+foo$bar$baz
+```
+
+## `regexp.Split`
+
+Splits `input` into sub-strings, separated by the expression.
+
+This can be called with 2 or 3 arguments. When called with 2 arguments, the
+`n` argument (number of matches) will be set to `-1`, causing all sub-strings
+to be returned.
+
+This is equivalent to [`strings.SplitN`](../strings/#strings-splitn),
+except that regular expressions are supported.
+
+This function provides the same behaviour as Go's
+[`regexp.Split`](https://golang.org/pkg/regexp/#Regexp.Split) function.
+
+### Usage
+```go
+regexp.Split expression [false] input
+```
+
+```go
+input | regexp.Split expression [false]
+```
+
+### Arguments
+
+| name | description |
+|------|-------------|
+| `expression` | _(required)_ The regular expression |
+| `false` | _(optional)_ The number of matches to return |
+| `input` | _(required)_ The input to search |
+
+### Examples
+
+```console
+$ gomplate -i '{{ regexp.Split `[\s,.]` "foo bar,baz.qux" | toJSON}}'
+["foo","bar","baz","qux"]
+```
+```console
+$ gomplate -i '{{ "foo bar.baz,qux" | regexp.Split `[\s,.]` 3 | toJSON}}'
+["foo","bar","baz"]
+```
diff --git a/funcs/regexp.go b/funcs/regexp.go
index ad5578fb..344b5cf8 100644
--- a/funcs/regexp.go
+++ b/funcs/regexp.go
@@ -3,6 +3,8 @@ package funcs
import (
"sync"
+ "github.com/pkg/errors"
+
"github.com/hairyhenderson/gomplate/conv"
"github.com/hairyhenderson/gomplate/regexp"
)
@@ -26,12 +28,65 @@ func AddReFuncs(f map[string]interface{}) {
// ReFuncs -
type ReFuncs struct{}
-// Replace -
-func (f *ReFuncs) Replace(re, replacement string, input interface{}) string {
- return regexp.Replace(re, replacement, conv.ToString(input))
+// Find -
+func (f *ReFuncs) Find(re, input interface{}) (string, error) {
+ return regexp.Find(conv.ToString(re), conv.ToString(input))
+}
+
+// FindAll -
+func (f *ReFuncs) FindAll(args ...interface{}) ([]string, error) {
+ re := ""
+ n := 0
+ input := ""
+ switch len(args) {
+ case 2:
+ n = -1
+ re = conv.ToString(args[0])
+ input = conv.ToString(args[1])
+ case 3:
+ re = conv.ToString(args[0])
+ n = conv.ToInt(args[1])
+ input = conv.ToString(args[2])
+ default:
+ return nil, errors.Errorf("wrong number of args: want 2 or 3, got %d", len(args))
+ }
+ return regexp.FindAll(re, n, input)
}
// Match -
-func (f *ReFuncs) Match(re string, input interface{}) bool {
- return regexp.Match(re, conv.ToString(input))
+func (f *ReFuncs) Match(re, input interface{}) bool {
+ return regexp.Match(conv.ToString(re), conv.ToString(input))
+}
+
+// Replace -
+func (f *ReFuncs) Replace(re, replacement, input interface{}) string {
+ return regexp.Replace(conv.ToString(re),
+ conv.ToString(replacement),
+ conv.ToString(input))
+}
+
+// ReplaceLiteral -
+func (f *ReFuncs) ReplaceLiteral(re, replacement, input interface{}) (string, error) {
+ return regexp.ReplaceLiteral(conv.ToString(re),
+ conv.ToString(replacement),
+ conv.ToString(input))
+}
+
+// Split -
+func (f *ReFuncs) Split(args ...interface{}) ([]string, error) {
+ re := ""
+ n := -1
+ input := ""
+ switch len(args) {
+ case 2:
+ re = conv.ToString(args[0])
+ input = conv.ToString(args[1])
+ case 3:
+ re = conv.ToString(args[0])
+ n = conv.ToInt(args[1])
+ input = conv.ToString(args[2])
+ default:
+ return nil, errors.Errorf("wrong number of args: want 2 or 3, got %d", len(args))
+ }
+ return regexp.Split(re, n, input)
}
diff --git a/funcs/regexp_test.go b/funcs/regexp_test.go
index 31671da0..905c4146 100644
--- a/funcs/regexp_test.go
+++ b/funcs/regexp_test.go
@@ -15,3 +15,100 @@ func TestMatch(t *testing.T) {
re := &ReFuncs{}
assert.True(t, re.Match(`i\ `, "hi world"))
}
+
+func TestFind(t *testing.T) {
+ re := &ReFuncs{}
+ f, err := re.Find(`[a-z]+`, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.Equal(t, "foo", f)
+
+ _, err = re.Find(`[a-`, "")
+ assert.Error(t, err)
+
+ f, err = re.Find("4", 42)
+ assert.NoError(t, err)
+ assert.Equal(t, "4", f)
+
+ f, err = re.Find(false, 42)
+ assert.NoError(t, err)
+ assert.Equal(t, "", f)
+}
+
+func TestFindAll(t *testing.T) {
+ re := &ReFuncs{}
+ f, err := re.FindAll(`[a-z]+`, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar", "baz"}, f)
+
+ f, err = re.FindAll(`[a-z]+`, -1, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar", "baz"}, f)
+
+ _, err = re.FindAll(`[a-`, "")
+ assert.Error(t, err)
+
+ _, err = re.FindAll("")
+ assert.Error(t, err)
+
+ _, err = re.FindAll("", "", "", "")
+ assert.Error(t, err)
+
+ f, err = re.FindAll(`[a-z]+`, 0, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.Nil(t, f)
+
+ f, err = re.FindAll(`[a-z]+`, 2, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar"}, f)
+
+ f, err = re.FindAll(`[a-z]+`, 14, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar", "baz"}, f)
+
+ f, err = re.FindAll(`qux`, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.Nil(t, f)
+}
+
+func TestSplit(t *testing.T) {
+ re := &ReFuncs{}
+ f, err := re.Split(` `, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar", "baz"}, f)
+
+ f, err = re.Split(`\s+`, -1, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar", "baz"}, f)
+
+ _, err = re.Split(`[a-`, "")
+ assert.Error(t, err)
+
+ _, err = re.Split("")
+ assert.Error(t, err)
+
+ _, err = re.Split("", "", "", "")
+ assert.Error(t, err)
+
+ f, err = re.Split(` `, 0, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.Nil(t, f)
+
+ f, err = re.Split(`\s+`, 2, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar baz"}, f)
+
+ f, err = re.Split(`\s`, 14, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "", "bar", "baz"}, f)
+
+ f, err = re.Split(`[\s,.]`, 14, `foo bar.baz,qux`)
+ assert.NoError(t, err)
+ assert.EqualValues(t, []string{"foo", "bar", "baz", "qux"}, f)
+}
+
+func TestReplaceLiteral(t *testing.T) {
+ re := &ReFuncs{}
+ r, err := re.ReplaceLiteral("i", "ello$1", "hi world")
+ assert.NoError(t, err)
+ assert.Equal(t, "hello$1 world", r)
+}
diff --git a/regexp/regexp.go b/regexp/regexp.go
index 8aeaa43c..a6cadc74 100644
--- a/regexp/regexp.go
+++ b/regexp/regexp.go
@@ -2,10 +2,22 @@ package regexp
import stdre "regexp"
-// Replace -
-func Replace(expression, replacement, input string) string {
- re := stdre.MustCompile(expression)
- return re.ReplaceAllString(input, replacement)
+// Find -
+func Find(expression, input string) (string, error) {
+ re, err := stdre.Compile(expression)
+ if err != nil {
+ return "", err
+ }
+ return re.FindString(input), nil
+}
+
+// FindAll -
+func FindAll(expression string, n int, input string) ([]string, error) {
+ re, err := stdre.Compile(expression)
+ if err != nil {
+ return nil, err
+ }
+ return re.FindAllString(input, n), nil
}
// Match -
@@ -13,3 +25,27 @@ func Match(expression, input string) bool {
re := stdre.MustCompile(expression)
return re.MatchString(input)
}
+
+// Replace -
+func Replace(expression, replacement, input string) string {
+ re := stdre.MustCompile(expression)
+ return re.ReplaceAllString(input, replacement)
+}
+
+// ReplaceLiteral -
+func ReplaceLiteral(expression, replacement, input string) (string, error) {
+ re, err := stdre.Compile(expression)
+ if err != nil {
+ return "", err
+ }
+ return re.ReplaceAllLiteralString(input, replacement), nil
+}
+
+// Split -
+func Split(expression string, n int, input string) ([]string, error) {
+ re, err := stdre.Compile(expression)
+ if err != nil {
+ return nil, err
+ }
+ return re.Split(input, n), nil
+}
diff --git a/regexp/regexp_test.go b/regexp/regexp_test.go
index 15adccd4..89f6cb86 100644
--- a/regexp/regexp_test.go
+++ b/regexp/regexp_test.go
@@ -6,18 +6,104 @@ import (
"github.com/stretchr/testify/assert"
)
-func TestReplace(t *testing.T) {
- assert.Equal(t, "-T-T-", Replace("a(x*)b", "T", "-ab-axxb-"))
- assert.Equal(t, "--xx-", Replace("a(x*)b", "$1", "-ab-axxb-"))
- assert.Equal(t, "---", Replace("a(x*)b", "$1W", "-ab-axxb-"))
- assert.Equal(t, "-W-xxW-", Replace("a(x*)b", "${1}W", "-ab-axxb-"))
+func TestFind(t *testing.T) {
+ f, err := Find(`[a-z]+`, `foo bar baz`)
+ assert.NoError(t, err)
+ assert.Equal(t, "foo", f)
- assert.Equal(t, "Turing, Alan", Replace("(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)", "${last}, ${first}", "Alan Turing"))
+ _, err = Find(`[a-`, "")
+ assert.Error(t, err)
}
+func TestFindAll(t *testing.T) {
+ _, err := FindAll(`[a-`, 42, "")
+ assert.Error(t, err)
+
+ testdata := []struct {
+ re string
+ n int
+ in string
+ expected []string
+ }{
+ {`[a-z]+`, -1, `foo bar baz`, []string{"foo", "bar", "baz"}},
+ {`[a-z]+`, 0, `foo bar baz`, nil},
+ {`[a-z]+`, 2, `foo bar baz`, []string{"foo", "bar"}},
+ {`[a-z]+`, 14, `foo bar baz`, []string{"foo", "bar", "baz"}},
+ }
+
+ for _, d := range testdata {
+ f, err := FindAll(d.re, d.n, d.in)
+ assert.NoError(t, err)
+ assert.EqualValues(t, d.expected, f)
+ }
+}
func TestMatch(t *testing.T) {
assert.True(t, Match(`^[a-z]+\[[0-9]+\]$`, "adam[23]"))
assert.True(t, Match(`^[a-z]+\[[0-9]+\]$`, "eve[7]"))
assert.False(t, Match(`^[a-z]+\[[0-9]+\]$`, "Job[48]"))
assert.False(t, Match(`^[a-z]+\[[0-9]+\]$`, "snakey"))
}
+
+func TestReplace(t *testing.T) {
+ testdata := []struct {
+ expected string
+ expression string
+ replacement string
+ input string
+ }{
+ {"-T-T-", "a(x*)b", "T", "-ab-axxb-"},
+ {"--xx-", "a(x*)b", "$1", "-ab-axxb-"},
+ {"---", "a(x*)b", "$1W", "-ab-axxb-"},
+ {"-W-xxW-", "a(x*)b", "${1}W", "-ab-axxb-"},
+ {"Turing, Alan", "(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)", "${last}, ${first}", "Alan Turing"},
+ }
+ for _, d := range testdata {
+ assert.Equal(t, d.expected, Replace(d.expression, d.replacement, d.input))
+ }
+}
+
+func TestReplaceLiteral(t *testing.T) {
+ _, err := ReplaceLiteral(`[a-`, "", "")
+ assert.Error(t, err)
+
+ testdata := []struct {
+ expected string
+ expression string
+ replacement string
+ input string
+ }{
+ {"-T-T-", "a(x*)b", "T", "-ab-axxb-"},
+ {"-$1-$1-", "a(x*)b", "$1", "-ab-axxb-"},
+ {"-$1W-$1W-", "a(x*)b", "$1W", "-ab-axxb-"},
+ {"-${1}W-${1}W-", "a(x*)b", "${1}W", "-ab-axxb-"},
+ {"${last}, ${first}", "(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)", "${last}, ${first}", "Alan Turing"},
+ }
+ for _, d := range testdata {
+ r, err := ReplaceLiteral(d.expression, d.replacement, d.input)
+ assert.NoError(t, err)
+ assert.Equal(t, d.expected, r)
+ }
+}
+
+func TestSplit(t *testing.T) {
+ _, err := Split(`[a-`, 42, "")
+ assert.Error(t, err)
+
+ testdata := []struct {
+ re string
+ n int
+ in string
+ expected []string
+ }{
+ {`\s+`, -1, "foo bar baz\tqux", []string{"foo", "bar", "baz", "qux"}},
+ {`,`, 0, `foo bar baz`, nil},
+ {` `, 2, `foo bar baz`, []string{"foo", "bar baz"}},
+ {`[\s,.]`, 14, `foo bar.baz,qux`, []string{"foo", "bar", "baz", "qux"}},
+ }
+
+ for _, d := range testdata {
+ f, err := Split(d.re, d.n, d.in)
+ assert.NoError(t, err)
+ assert.EqualValues(t, d.expected, f)
+ }
+}