shithub: hugo

Download patch

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()