mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-19 21:21:39 +02:00
tpl: Refactor and fix substr logic
Fix miscalculations when start is negative. Results should now match PHP substr. Fixes #7993
This commit is contained in:
committed by
Bjørn Erik Pedersen
parent
32d4bf68da
commit
64789fb5dc
@@ -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 s > e {
|
||||
return "", fmt.Errorf("calculated start position greater than end position: %d > %d", s, e)
|
||||
}
|
||||
if e > len(asRunes) {
|
||||
e = len(asRunes)
|
||||
if start >= end {
|
||||
return "", fmt.Errorf("calculated start position greater than end position: %d > %d", start, end)
|
||||
}
|
||||
|
||||
return string(asRunes[s:e]), nil
|
||||
if end < 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if end > rlen {
|
||||
end = rlen
|
||||
}
|
||||
|
||||
return string(asRunes[start:end]), nil
|
||||
}
|
||||
|
||||
// Title returns a copy of the input s with all Unicode letters that begin words
|
||||
|
Reference in New Issue
Block a user