Skip to content

Commit fb0e5d8

Browse files
ofavreclaude
authored andcommitted
Enhance slice filter with Unicode support and array slicing (#72)
- Add proper Unicode handling using runes instead of regex - Fix performance issues with strings longer than 1000 characters - Add support for slicing arrays/slices, not just strings - Improve bounds checking: clamp out-of-bounds negative indices to 0 - Add comprehensive test coverage: - Unicode strings (Japanese characters) - Very long strings (10,000+ characters) - Out-of-bounds indices (positive and negative) - Array slicing from split operations Co-authored-by: Olivier Favre <olivier@wonderpush.com> Resolves #72
1 parent 4237459 commit fb0e5d8

2 files changed

Lines changed: 65 additions & 20 deletions

File tree

filters/standard_filters.go

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -194,28 +194,55 @@ func AddStandardFilters(fd FilterDictionary) { //nolint: gocyclo
194194
return strings.Replace(s, old, n, 1)
195195
})
196196
fd.AddFilter("sort_natural", sortNaturalFilter)
197-
fd.AddFilter("slice", func(s string, start int, length func(int) int) string {
198-
if len(s) == 0 {
199-
return ""
200-
}
201-
202-
ss := []rune(s)
203-
n := length(1)
204-
205-
if start < 0 {
206-
start = len(ss) + start
197+
fd.AddFilter("slice", func(v interface{}, start int, length func(int) int) interface{} {
198+
// Are we in the []byte case? Transform []byte to string
199+
if b, ok := v.([]byte); ok {
200+
v = string(b)
207201
}
208-
209-
if start < 0 {
210-
return ""
202+
// Are we in the string case?
203+
if s, ok := v.(string); ok {
204+
// Work on runes, not chars
205+
runes := []rune(s)
206+
n := length(1)
207+
if start < 0 {
208+
start = len(runes) + start
209+
if start < 0 {
210+
start = 0
211+
}
212+
}
213+
if start > len(runes) {
214+
start = len(runes)
215+
}
216+
end := start + n
217+
if end > len(runes) {
218+
end = len(runes)
219+
}
220+
return string(runes[start:end])
211221
}
212-
213-
end := start + n
214-
if end > len(ss) {
215-
end = len(ss)
222+
// Are we in the slice case?
223+
// A type test cannot suffice because []T and []U are different types, so we must use conversion.
224+
var slice []interface{}
225+
if sliceIface, err := values.Convert(v, reflect.TypeOf(slice)); err == nil {
226+
var ok bool
227+
if slice, ok = sliceIface.([]interface{}); ok {
228+
n := length(1)
229+
if start < 0 {
230+
start = len(slice) + start
231+
if start < 0 {
232+
start = 0
233+
}
234+
}
235+
if start > len(slice) {
236+
start = len(slice)
237+
}
238+
end := start + n
239+
if end > len(slice) {
240+
end = len(slice)
241+
}
242+
return slice[start:end]
243+
}
216244
}
217-
218-
return string(ss[start:end])
245+
return nil
219246
})
220247
fd.AddFilter("split", splitFilter)
221248
fd.AddFilter("strip_html", func(s string) string {

filters/standard_filters_test.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package filters
22

33
import (
44
"fmt"
5+
"strings"
56
"testing"
67
"time"
78

@@ -112,7 +113,24 @@ Liquid" | slice: 0`, "L"},
112113
Liquid" | slice: 2, 4`, "quid"},
113114
{`"Liquid" | slice: -3, 2`, "ui"},
114115
{`"" | slice: 1`, ""},
115-
{`"Liquid" | slice: -7`, ""},
116+
{`"Liquid" | slice: 2, 100`, "quid"},
117+
{`"Liquid" | slice: 100`, ""},
118+
{`"Liquid" | slice: 100, 200`, ""},
119+
{`"Liquid" | slice: -100`, "L"},
120+
{`"Liquid" | slice: -100, 200`, "Liquid"},
121+
{`"白鵬翔" | slice: 0`, "白"},
122+
{`"白鵬翔" | slice: 1`, "鵬"},
123+
{`"白鵬翔" | slice: 2`, "翔"},
124+
{`"白鵬翔" | slice: 0, 2`, "白鵬"},
125+
{`"白鵬翔" | slice: 1, 2`, "鵬翔"},
126+
{`"白鵬翔" | slice: 100, 200`, ""},
127+
{`"白鵬翔" | slice: -100`, "白"},
128+
{`"白鵬翔" | slice: -100, 200`, "白鵬翔"},
129+
{`">` + strings.Repeat(".", 10000) + `<" | slice: 1, 10000`, strings.Repeat(".", 10000)},
130+
{`"a,b,c" | split: "," | slice: -1 | join`, "c"},
131+
{`"a,b,c" | split: "," | slice: 1, 1 | join`, "b"},
132+
{`"a,b,c" | split: "," | slice: 0, 2 | join`, "a b"},
133+
{`"a,b,c" | split: "," | slice: 1, 2 | join`, "b c"},
116134

117135
{`"a/b/c" | split: '/' | join: '-'`, "a-b-c"},
118136
{`"a/b/" | split: '/' | join: '-'`, "a-b"},

0 commit comments

Comments
 (0)