diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2019-03-18 20:42:40 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-03-18 20:42:40 -0400 |
| commit | d2a6b5201089b14a99c75fb5e4ff4370bc07e4b8 (patch) | |
| tree | 4a9e4553047003ad09ede4b3047b816bad9289d0 | |
| parent | 142279a94ed69684109f01ddfac2b5a29ba7264b (diff) | |
| parent | 9c45b8e6e9abff588f3ae439cfac1b55e28faa95 (diff) | |
Merge pull request #518 from hairyhenderson/add-runecount-func
Adding strings.RuneCount function
| -rw-r--r-- | docs-src/content/functions/strings.yml | 23 | ||||
| -rw-r--r-- | docs/content/functions/strings.md | 37 | ||||
| -rw-r--r-- | funcs/strings.go | 10 | ||||
| -rw-r--r-- | funcs/strings_test.go | 28 |
4 files changed, 98 insertions, 0 deletions
diff --git a/docs-src/content/functions/strings.yml b/docs-src/content/functions/strings.yml index 9dbc886f..b3062dc4 100644 --- a/docs-src/content/functions/strings.yml +++ b/docs-src/content/functions/strings.yml @@ -479,6 +479,29 @@ funcs: http://example.com/a/very/long/url which should not be broken + - name: strings.RuneCount + description: | + Return the number of _runes_ (Unicode code-points) contained within the + input. This is similar to the built-in `len` function, but `len` counts + the length in _bytes_. The length of an input containing multi-byte + code-points should therefore be measured with `strings.RuneCount`. + + Inputs will first be converted to strings, and multiple inputs are + concatenated. + + This wraps Go's [`utf8.RuneCountInString`](https://golang.org/pkg/unicode/utf8/#RuneCountInString) + function. + pipeline: true + arguments: + - name: input + required: true + description: the input(s) to measure + examples: + - | + $ gomplate -i '{{ range (slice "\u03a9" "\u0030" "\u1430") }}{{ printf "%s is %d bytes and %d runes\n" . (len .) (strings.RuneCount .) }}{{ end }}' + Ω is 2 bytes and 1 runes + 0 is 1 bytes and 1 runes + ᐰ is 3 bytes and 1 runes - name: contains description: | **See [`strings.Contains`](#strings-contains) for a pipeline-compatible version** diff --git a/docs/content/functions/strings.md b/docs/content/functions/strings.md index df59bfd6..26254b7a 100644 --- a/docs/content/functions/strings.md +++ b/docs/content/functions/strings.md @@ -804,6 +804,43 @@ which should not be broken ``` +## `strings.RuneCount` + +Return the number of _runes_ (Unicode code-points) contained within the +input. This is similar to the built-in `len` function, but `len` counts +the length in _bytes_. The length of an input containing multi-byte +code-points should therefore be measured with `strings.RuneCount`. + +Inputs will first be converted to strings, and multiple inputs are +concatenated. + +This wraps Go's [`utf8.RuneCountInString`](https://golang.org/pkg/unicode/utf8/#RuneCountInString) +function. + +### Usage + +```go +strings.RuneCount input +``` +```go +input | strings.RuneCount +``` + +### Arguments + +| name | description | +|------|-------------| +| `input` | _(required)_ the input(s) to measure | + +### Examples + +```console +$ gomplate -i '{{ range (slice "\u03a9" "\u0030" "\u1430") }}{{ printf "%s is %d bytes and %d runes\n" . (len .) (strings.RuneCount .) }}{{ end }}' +Ω is 2 bytes and 1 runes +0 is 1 bytes and 1 runes +ᐰ is 3 bytes and 1 runes +``` + ## `contains` **See [`strings.Contains`](#strings-contains) for a pipeline-compatible version** diff --git a/funcs/strings.go b/funcs/strings.go index df070a26..d8fa8641 100644 --- a/funcs/strings.go +++ b/funcs/strings.go @@ -8,6 +8,7 @@ package funcs import ( "fmt" "sync" + "unicode/utf8" "github.com/Masterminds/goutils" "github.com/hairyhenderson/gomplate/conv" @@ -262,3 +263,12 @@ func (f *StringFuncs) WordWrap(args ...interface{}) (string, error) { } return gompstrings.WordWrap(in, opts), nil } + +// RuneCount - like len(s), but for runes +func (f *StringFuncs) RuneCount(args ...interface{}) (int, error) { + s := "" + for _, arg := range args { + s += conv.ToString(arg) + } + return utf8.RuneCountInString(s), nil +} diff --git a/funcs/strings_test.go b/funcs/strings_test.go index 04a97bcc..c79e5d24 100644 --- a/funcs/strings_test.go +++ b/funcs/strings_test.go @@ -144,3 +144,31 @@ func TestSquote(t *testing.T) { assert.Equal(t, d.out, sf.Squote(d.in)) } } + +func TestRuneCount(t *testing.T) { + sf := &StringFuncs{} + + n, err := sf.RuneCount("") + assert.NoError(t, err) + assert.Equal(t, 0, n) + + n, err = sf.RuneCount("foo") + assert.NoError(t, err) + assert.Equal(t, 3, n) + + n, err = sf.RuneCount("foo", "bar") + assert.NoError(t, err) + assert.Equal(t, 6, n) + + n, err = sf.RuneCount(42, true) + assert.NoError(t, err) + assert.Equal(t, 6, n) + + n, err = sf.RuneCount("😂\U0001F602") + assert.NoError(t, err) + assert.Equal(t, 2, n) + + n, err = sf.RuneCount("\U0001F600", 3.14) + assert.NoError(t, err) + assert.Equal(t, 5, n) +} |
