Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tpl
diff options
context:
space:
mode:
authorCameron Moore <moorereason@gmail.com>2020-11-28 08:43:01 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2020-11-28 13:53:46 +0300
commit64789fb5dcf8326f14f13d69a2576ae3aa2bbbaa (patch)
tree050176b890a867c3d175a368a69785569ca072e4 /tpl
parent32d4bf68da7d16302f138dde343c70f9667933c4 (diff)
tpl: Refactor and fix substr logic
Fix miscalculations when start is negative. Results should now match PHP substr. Fixes #7993
Diffstat (limited to 'tpl')
-rw-r--r--tpl/strings/strings.go67
-rw-r--r--tpl/strings/strings_test.go11
2 files changed, 45 insertions, 33 deletions
diff --git a/tpl/strings/strings.go b/tpl/strings/strings.go
index c87b532d3..9427d8e8a 100644
--- a/tpl/strings/strings.go
+++ b/tpl/strings/strings.go
@@ -279,64 +279,73 @@ func (ns *Namespace) Split(a interface{}, delimiter string) ([]string, error) {
// if length is given and is negative, then that many characters will be omitted from
// the end of string.
func (ns *Namespace) Substr(a interface{}, nums ...interface{}) (string, error) {
- aStr, err := cast.ToStringE(a)
+ s, err := cast.ToStringE(a)
if err != nil {
return "", err
}
- var start, length int
+ asRunes := []rune(s)
+ rlen := len(asRunes)
- asRunes := []rune(aStr)
+ var start, length int
switch len(nums) {
case 0:
- return "", errors.New("too less arguments")
+ return "", errors.New("too few arguments")
case 1:
if start, err = cast.ToIntE(nums[0]); err != nil {
- return "", errors.New("start argument must be integer")
+ return "", errors.New("start argument must be an integer")
}
- length = len(asRunes)
+ length = rlen
case 2:
if start, err = cast.ToIntE(nums[0]); err != nil {
- return "", errors.New("start argument must be integer")
+ return "", errors.New("start argument must be an integer")
}
if length, err = cast.ToIntE(nums[1]); err != nil {
- return "", errors.New("length argument must be integer")
+ return "", errors.New("length argument must be an integer")
}
default:
return "", errors.New("too many arguments")
}
- if start < -len(asRunes) {
+ if rlen == 0 {
+ return "", nil
+ }
+
+ if start < 0 {
+ start += rlen
+ }
+
+ // start was originally negative beyond rlen
+ if start < 0 {
start = 0
}
- if start > len(asRunes) {
- return "", fmt.Errorf("start position out of bounds for %d-byte string", len(aStr))
+
+ if start > rlen-1 {
+ return "", fmt.Errorf("start position out of bounds for %d-byte string", rlen)
}
- var s, e int
- if start >= 0 && length >= 0 {
- s = start
- e = start + length
- } else if start < 0 && length >= 0 {
- s = len(asRunes) + start - length + 1
- e = len(asRunes) + start + 1
- } else if start >= 0 && length < 0 {
- s = start
- e = len(asRunes) + length
- } else {
- s = len(asRunes) + start
- e = len(asRunes) + length
+ end := rlen
+
+ if length < 0 {
+ end += length
+ } else if length > 0 {
+ end = start + length
+ }
+
+ if start >= end {
+ return "", fmt.Errorf("calculated start position greater than end position: %d > %d", start, end)
}
- if s > e {
- return "", fmt.Errorf("calculated start position greater than end position: %d > %d", s, e)
+ if end < 0 {
+ return "", nil
}
- if e > len(asRunes) {
- e = len(asRunes)
+
+ if end > rlen {
+ end = rlen
}
- return string(asRunes[s:e]), nil
+ return string(asRunes[start:end]), nil
}
// Title returns a copy of the input s with all Unicode letters that begin words
diff --git a/tpl/strings/strings_test.go b/tpl/strings/strings_test.go
index 6a14acd78..bb90200c0 100644
--- a/tpl/strings/strings_test.go
+++ b/tpl/strings/strings_test.go
@@ -441,8 +441,11 @@ func TestSubstr(t *testing.T) {
}{
{"abc", 1, 2, "bc"},
{"abc", 0, 1, "a"},
- {"abcdef", -1, 2, "ef"},
- {"abcdef", -3, 3, "bcd"},
+ {"abcdef", -1, 2, "f"},
+ {"abcdef", -3, 3, "def"},
+ {"abcdef", -1, nil, "f"},
+ {"abcdef", -2, nil, "ef"},
+ {"abcdef", -3, 1, "d"},
{"abcdef", 0, -1, "abcde"},
{"abcdef", 2, -1, "cde"},
{"abcdef", 4, -4, false},
@@ -480,12 +483,12 @@ func TestSubstr(t *testing.T) {
}
if b, ok := test.expect.(bool); ok && !b {
- c.Assert(err, qt.Not(qt.IsNil))
+ c.Assert(err, qt.Not(qt.IsNil), qt.Commentf("%v", test))
continue
}
c.Assert(err, qt.IsNil)
- c.Assert(result, qt.Equals, test.expect)
+ c.Assert(result, qt.Equals, test.expect, qt.Commentf("%v", test))
}
_, err = ns.Substr("abcdef")