ref: 019bd5576be87c9f06b6a928ede1a5e78677f7b3
parent: c3115292a7f2d2623cb45054a361e997ad9330c9
author: David E. Wheeler <[email protected]>
date: Mon Jun 4 09:47:03 EDT 2018
tpl/strings: strings.RuneCount
--- /dev/null
+++ b/docs/content/en/functions/strings.RuneCount.md
@@ -1,0 +1,28 @@
+---
+title: strings.RuneCount
+description: Determines the number of runes in a string.
+godocref:
+date: 2018-06-01
+publishdate: 2018-06-01
+lastmod: 2018-06-01
+categories: [functions]
+menu:
+ docs:
+ parent: "functions"
+keywords: [counting, character count, length, rune length, rune count]
+signature: ["strings.RuneCount INPUT"]
+workson: []
+hugoversion:
+relatedfuncs: ["len", "countrunes"]
+deprecated: false
+aliases: []
+---
+
+In contrast with `strings.CountRunes` function, which strips HTML and whitespace before counting runes, `strings.RuneCount` simply counts all the runes in a string. It relies on the Go [`utf8.RuneCountInString`] function.
+
+```
+{{ "Hello, 世界" | strings.RuneCount }}
+<!-- outputs a content length of 9 runes. -->
+```
+
+[`utf8.RuneCount`]: https://golang.org/pkg/unicode/utf8/#RuneCount
\ No newline at end of file
--- a/docs/data/docs.json
+++ b/docs/data/docs.json
@@ -3146,7 +3146,25 @@
"Aliases": [
"countrunes"
],
- "Examples": []
+ "Examples": [
+ [
+ "{{ \"Hello, 世界\" | countrunes }}",
+ "8"
+ ]
+ ]
+ },
+ "RuneCount": {
+ "Description": "RuneCount returns the number of runes in s",
+ "Args": [
+ "s"
+ ],
+ "Aliases": [],
+ "Examples": [
+ [
+ "{{ \"Hello, 世界\" | strings.RuneCount }}",
+ "9"
+ ]
+ ]
},
"CountWords": {
"Description": "CountWords returns the approximate word count in s.",
--- a/tpl/strings/init.go
+++ b/tpl/strings/init.go
@@ -41,6 +41,11 @@
[][2]string{},
)
+ ns.AddMethodMapping(ctx.RuneCount,
+ nil,
+ [][2]string{},
+ )
+
ns.AddMethodMapping(ctx.CountWords,
[]string{"countwords"},
[][2]string{},
--- a/tpl/strings/strings.go
+++ b/tpl/strings/strings.go
@@ -57,6 +57,15 @@
return counter, nil
}
+// RuneCount returns the number of runes in s.
+func (ns *Namespace) RuneCount(s interface{}) (int, error) {
+ ss, err := cast.ToStringE(s)
+ if err != nil {
+ return 0, fmt.Errorf("Failed to convert content to string: %s", err)
+ }
+ return utf8.RuneCountInString(ss), nil
+}
+
// CountWords returns the approximate word count in s.
func (ns *Namespace) CountWords(s interface{}) (int, error) {
ss, err := cast.ToStringE(s)
--- a/tpl/strings/strings_test.go
+++ b/tpl/strings/strings_test.go
@@ -173,6 +173,33 @@
}
}
+func TestRuneCount(t *testing.T) {
+ t.Parallel()
+
+ for i, test := range []struct {
+ s interface{}
+ expect interface{}
+ }{
+ {"foo bar", 7},
+ {"旁边", 2},
+ {`<div class="test">旁边</div>`, 26},
+ // errors
+ {tstNoStringer{}, false},
+ } {
+ errMsg := fmt.Sprintf("[%d] %v", i, test.s)
+
+ result, err := ns.RuneCount(test.s)
+
+ if b, ok := test.expect.(bool); ok && !b {
+ require.Error(t, err, errMsg)
+ continue
+ }
+
+ require.NoError(t, err, errMsg)
+ assert.Equal(t, test.expect, result, errMsg)
+ }
+}
+
func TestCountWords(t *testing.T) {
t.Parallel()