gofront 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/package.json +10 -38
- package/src/backend/js/expressions.js +2060 -389
- package/src/backend/js/index.js +586 -174
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +936 -1644
- package/src/backend/js/statements.js +1349 -132
- package/src/backend/js/stdlib/index.js +51 -94
- package/src/backend/js/templ.js +67 -118
- package/src/backend/js/type-info.js +436 -0
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +80 -0
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +753 -872
- package/src/backend/wasm/emit-builtins.js +914 -237
- package/src/backend/wasm/emit-exprs.js +1456 -195
- package/src/backend/wasm/emit-maps.js +78 -380
- package/src/backend/wasm/emit-stmts.js +1659 -214
- package/src/backend/wasm/emit.js +614 -88
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +491 -0
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +406 -3195
- package/src/backend/wasm/method-expr.js +392 -0
- package/src/backend/wasm/module-emitter.js +1615 -0
- package/src/backend/wasm/monomorph.js +164 -9
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +249 -0
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -37
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/types.js +260 -27
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +241 -11
- package/src/{test-runner.js → cli/test-runner.js} +188 -122
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +202 -386
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +203 -62
- package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
- package/src/{tokens.js → lexer/tokens.js} +2 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +737 -0
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +318 -0
- package/src/lower/bounds.js +547 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +267 -64
- package/src/lower/embedding.js +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +33 -19
- package/src/lower/json-codecs.js +1379 -0
- package/src/lower/ownership.js +47 -8
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +150 -0
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +83 -15
- package/src/parser/expressions.js +110 -18
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +38 -22
- package/src/{templ-parser.js → parser/templ.js} +179 -17
- package/src/parser/types.js +70 -9
- package/src/resolver.js +21 -1
- package/src/typechecker/assignability.js +291 -19
- package/src/typechecker/const-fold.js +399 -0
- package/src/typechecker/constants.js +282 -0
- package/src/typechecker/expressions.js +1220 -183
- package/src/typechecker/index.js +659 -92
- package/src/typechecker/init-order.js +426 -0
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +613 -62
- package/src/typechecker/statements.js +212 -20
- package/src/typechecker/stdlib/excluded.js +902 -0
- package/src/typechecker/stdlib/index.js +38 -0
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +11 -2
- package/src/typechecker/types.js +268 -514
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +871 -0
- package/stdlib/internal/jsonrt/enc.go +516 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +658 -0
- package/stdlib/io/io.go +502 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +272 -0
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +500 -0
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +526 -0
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +250 -0
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -46
- package/src/backend/js/stdlib/builder.js +0 -63
- package/src/backend/js/stdlib/bytes.js +0 -122
- package/src/backend/js/stdlib/errors.js +0 -44
- package/src/backend/js/stdlib/fmt.js +0 -178
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -972
- package/src/backend/js/stdlib/maps.js +0 -45
- package/src/backend/js/stdlib/math.js +0 -69
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -24
- package/src/backend/js/stdlib/slices.js +0 -77
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -74
- package/src/backend/js/stdlib/strings.js +0 -222
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -34
- package/src/backend/js/stdlib/time.js +0 -128
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- package/src/backend/wasm/stdlib/bytes.js +0 -5039
- package/src/backend/wasm/stdlib/core.js +0 -8903
- package/src/backend/wasm/stdlib/io.js +0 -2161
- package/src/backend/wasm/stdlib/packages.js +0 -2400
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -1200
- package/src/typechecker/stdlib/core.js +0 -801
- package/src/typechecker/stdlib/extended.js +0 -914
- package/src/typechecker/stdlib.js +0 -22
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
|
@@ -0,0 +1,807 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
// Package strings implements simple functions to manipulate UTF-8 encoded
|
|
6
|
+
// strings, written in Go over the real package's algorithms. Only Builder
|
|
7
|
+
// is left to the backends.
|
|
8
|
+
//
|
|
9
|
+
// GoFront strings are host strings, so offsets, lengths and slice bounds
|
|
10
|
+
// count UTF-16 code units, not UTF-8 bytes: Index returns a value that
|
|
11
|
+
// s[i:] accepts, and strings with only ASCII characters behave exactly as
|
|
12
|
+
// in Go. Runes are code points, and a lone surrogate reads as RuneError.
|
|
13
|
+
// The search, split, join, replace, case and trim functions keep host
|
|
14
|
+
// fast paths as natives that give the results the Go bodies give.
|
|
15
|
+
package strings
|
|
16
|
+
|
|
17
|
+
import (
|
|
18
|
+
"iter"
|
|
19
|
+
"unicode"
|
|
20
|
+
"unicode/utf8"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
// isSpace is unicode.IsSpace as a func(rune) bool.
|
|
24
|
+
func isSpace(r rune) bool {
|
|
25
|
+
return unicode.IsSpace(r)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func upperRune(r rune) rune { return unicode.ToUpper(r) }
|
|
29
|
+
func lowerRune(r rune) rune { return unicode.ToLower(r) }
|
|
30
|
+
|
|
31
|
+
// validRune reports whether r is a code point a string can hold.
|
|
32
|
+
func validRune(r rune) bool {
|
|
33
|
+
return r >= 0 && r <= 0x10FFFF && (r < 0xD800 || r > 0xDFFF)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Clone returns a fresh copy of s. Strings are immutable values here, so
|
|
37
|
+
// the copy is s itself.
|
|
38
|
+
func Clone(s string) string {
|
|
39
|
+
return s
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Compare returns an integer comparing two strings lexicographically.
|
|
43
|
+
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
|
|
44
|
+
func Compare(a, b string) int {
|
|
45
|
+
if a == b {
|
|
46
|
+
return 0
|
|
47
|
+
}
|
|
48
|
+
if a < b {
|
|
49
|
+
return -1
|
|
50
|
+
}
|
|
51
|
+
return +1
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── Search ────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
// Index returns the index of the first instance of substr in s, or -1 if
|
|
57
|
+
// substr is not present in s.
|
|
58
|
+
//
|
|
59
|
+
//gofront:native strings.Index
|
|
60
|
+
func Index(s, substr string) int {
|
|
61
|
+
n := len(substr)
|
|
62
|
+
for i := 0; i+n <= len(s); i++ {
|
|
63
|
+
if s[i:i+n] == substr {
|
|
64
|
+
return i
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return -1
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// LastIndex returns the index of the last instance of substr in s, or -1 if
|
|
71
|
+
// substr is not present in s.
|
|
72
|
+
//
|
|
73
|
+
//gofront:native strings.LastIndex
|
|
74
|
+
func LastIndex(s, substr string) int {
|
|
75
|
+
n := len(substr)
|
|
76
|
+
for i := len(s) - n; i >= 0; i-- {
|
|
77
|
+
if s[i:i+n] == substr {
|
|
78
|
+
return i
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return -1
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// IndexByte returns the index of the first instance of c in s, or -1 if c
|
|
85
|
+
// is not present in s.
|
|
86
|
+
//
|
|
87
|
+
//gofront:native strings.IndexByte
|
|
88
|
+
func IndexByte(s string, c byte) int {
|
|
89
|
+
return Index(s, string(rune(c)))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// LastIndexByte returns the index of the last instance of c in s, or -1 if
|
|
93
|
+
// c is not present in s.
|
|
94
|
+
//
|
|
95
|
+
//gofront:native strings.LastIndexByte
|
|
96
|
+
func LastIndexByte(s string, c byte) int {
|
|
97
|
+
return LastIndex(s, string(rune(c)))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// IndexRune returns the index of the first instance of the Unicode code
|
|
101
|
+
// point r, or -1 if rune is not present in s.
|
|
102
|
+
// If r is utf8.RuneError, it returns the first instance of U+FFFD.
|
|
103
|
+
// If r is not a valid code point, IndexRune returns -1.
|
|
104
|
+
//
|
|
105
|
+
//gofront:native strings.IndexRune
|
|
106
|
+
func IndexRune(s string, r rune) int {
|
|
107
|
+
if !validRune(r) {
|
|
108
|
+
return -1
|
|
109
|
+
}
|
|
110
|
+
return Index(s, string(r))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// IndexAny returns the index of the first instance of any Unicode code point
|
|
114
|
+
// from chars in s, or -1 if no Unicode code point from chars is present in s.
|
|
115
|
+
//
|
|
116
|
+
//gofront:native strings.IndexAny
|
|
117
|
+
func IndexAny(s, chars string) int {
|
|
118
|
+
m := -1
|
|
119
|
+
for _, c := range chars {
|
|
120
|
+
if i := IndexRune(s, c); i >= 0 && (m < 0 || i < m) {
|
|
121
|
+
m = i
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return m
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// LastIndexAny returns the index of the last instance of any Unicode code
|
|
128
|
+
// point from chars in s, or -1 if no Unicode code point from chars is
|
|
129
|
+
// present in s.
|
|
130
|
+
//
|
|
131
|
+
//gofront:native strings.LastIndexAny
|
|
132
|
+
func LastIndexAny(s, chars string) int {
|
|
133
|
+
m := -1
|
|
134
|
+
for _, c := range chars {
|
|
135
|
+
if !validRune(c) {
|
|
136
|
+
continue
|
|
137
|
+
}
|
|
138
|
+
if i := LastIndex(s, string(c)); i > m {
|
|
139
|
+
m = i
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return m
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Contains reports whether substr is within s.
|
|
146
|
+
//
|
|
147
|
+
//gofront:native strings.Contains
|
|
148
|
+
func Contains(s, substr string) bool {
|
|
149
|
+
return Index(s, substr) >= 0
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ContainsAny reports whether any Unicode code points in chars are within s.
|
|
153
|
+
//
|
|
154
|
+
//gofront:native strings.ContainsAny
|
|
155
|
+
func ContainsAny(s, chars string) bool {
|
|
156
|
+
return IndexAny(s, chars) >= 0
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ContainsRune reports whether the Unicode code point r is within s.
|
|
160
|
+
//
|
|
161
|
+
//gofront:native strings.ContainsRune
|
|
162
|
+
func ContainsRune(s string, r rune) bool {
|
|
163
|
+
return IndexRune(s, r) >= 0
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ContainsFunc reports whether any Unicode code points in s satisfy f(c).
|
|
167
|
+
func ContainsFunc(s string, f func(rune) bool) bool {
|
|
168
|
+
return IndexFunc(s, f) >= 0
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// HasPrefix reports whether the string s begins with prefix.
|
|
172
|
+
//
|
|
173
|
+
//gofront:native strings.HasPrefix
|
|
174
|
+
func HasPrefix(s, prefix string) bool {
|
|
175
|
+
return len(s) >= len(prefix) && s[:len(prefix)] == prefix
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// HasSuffix reports whether the string s ends with suffix.
|
|
179
|
+
//
|
|
180
|
+
//gofront:native strings.HasSuffix
|
|
181
|
+
func HasSuffix(s, suffix string) bool {
|
|
182
|
+
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Count counts the number of non-overlapping instances of substr in s.
|
|
186
|
+
// If substr is an empty string, Count returns 1 + the number of Unicode
|
|
187
|
+
// code points in s.
|
|
188
|
+
//
|
|
189
|
+
//gofront:native strings.Count
|
|
190
|
+
func Count(s, substr string) int {
|
|
191
|
+
if len(substr) == 0 {
|
|
192
|
+
return utf8.RuneCountInString(s) + 1
|
|
193
|
+
}
|
|
194
|
+
n := 0
|
|
195
|
+
for {
|
|
196
|
+
i := Index(s, substr)
|
|
197
|
+
if i == -1 {
|
|
198
|
+
return n
|
|
199
|
+
}
|
|
200
|
+
n++
|
|
201
|
+
s = s[i+len(substr):]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ── Split, join, repeat and replace ───────────────────────────
|
|
206
|
+
|
|
207
|
+
// explode splits s into a slice of single-code-point strings, up to n of
|
|
208
|
+
// them (the last holds the rest of s) when n > 0.
|
|
209
|
+
func explode(s string, n int) []string {
|
|
210
|
+
runes := []rune(s)
|
|
211
|
+
l := len(runes)
|
|
212
|
+
if n < 0 || n > l {
|
|
213
|
+
n = l
|
|
214
|
+
}
|
|
215
|
+
a := make([]string, n)
|
|
216
|
+
for i := 0; i < n-1; i++ {
|
|
217
|
+
a[i] = string(runes[i])
|
|
218
|
+
}
|
|
219
|
+
if n > 0 {
|
|
220
|
+
a[n-1] = string(runes[n-1:])
|
|
221
|
+
}
|
|
222
|
+
return a
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Generic split: splits after each instance of sep, including sepSave
|
|
226
|
+
// units of sep in the subarrays.
|
|
227
|
+
func genSplit(s, sep string, sepSave, n int) []string {
|
|
228
|
+
if n == 0 {
|
|
229
|
+
return nil
|
|
230
|
+
}
|
|
231
|
+
if sep == "" {
|
|
232
|
+
return explode(s, n)
|
|
233
|
+
}
|
|
234
|
+
if n < 0 {
|
|
235
|
+
n = Count(s, sep) + 1
|
|
236
|
+
}
|
|
237
|
+
if n > len(s)+1 {
|
|
238
|
+
n = len(s) + 1
|
|
239
|
+
}
|
|
240
|
+
a := make([]string, n)
|
|
241
|
+
n--
|
|
242
|
+
i := 0
|
|
243
|
+
for i < n {
|
|
244
|
+
m := Index(s, sep)
|
|
245
|
+
if m < 0 {
|
|
246
|
+
break
|
|
247
|
+
}
|
|
248
|
+
a[i] = s[:m+sepSave]
|
|
249
|
+
s = s[m+len(sep):]
|
|
250
|
+
i++
|
|
251
|
+
}
|
|
252
|
+
a[i] = s
|
|
253
|
+
return a[:i+1]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// SplitN slices s into substrings separated by sep and returns a slice of
|
|
257
|
+
// the substrings between those separators.
|
|
258
|
+
//
|
|
259
|
+
// The count determines the number of substrings to return:
|
|
260
|
+
// - n > 0: at most n substrings; the last substring will be the unsplit remainder;
|
|
261
|
+
// - n == 0: the result is nil (zero substrings);
|
|
262
|
+
// - n < 0: all substrings.
|
|
263
|
+
func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
|
|
264
|
+
|
|
265
|
+
// SplitAfterN slices s into substrings after each instance of sep and
|
|
266
|
+
// returns a slice of those substrings.
|
|
267
|
+
func SplitAfterN(s, sep string, n int) []string {
|
|
268
|
+
return genSplit(s, sep, len(sep), n)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Split slices s into all substrings separated by sep and returns a slice of
|
|
272
|
+
// the substrings between those separators.
|
|
273
|
+
//
|
|
274
|
+
// If s does not contain sep and sep is not empty, Split returns a
|
|
275
|
+
// slice of length 1 whose only element is s.
|
|
276
|
+
//
|
|
277
|
+
// If sep is empty, Split splits after each UTF-8 sequence.
|
|
278
|
+
//
|
|
279
|
+
//gofront:native strings.Split
|
|
280
|
+
func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
|
|
281
|
+
|
|
282
|
+
// SplitAfter slices s into all substrings after each instance of sep and
|
|
283
|
+
// returns a slice of those substrings.
|
|
284
|
+
func SplitAfter(s, sep string) []string {
|
|
285
|
+
return genSplit(s, sep, len(sep), -1)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Join concatenates the elements of its first argument to create a single
|
|
289
|
+
// string. The separator string sep is placed between elements in the
|
|
290
|
+
// resulting string.
|
|
291
|
+
//
|
|
292
|
+
//gofront:native strings.Join
|
|
293
|
+
func Join(elems []string, sep string) string {
|
|
294
|
+
switch len(elems) {
|
|
295
|
+
case 0:
|
|
296
|
+
return ""
|
|
297
|
+
case 1:
|
|
298
|
+
return elems[0]
|
|
299
|
+
}
|
|
300
|
+
var b Builder
|
|
301
|
+
b.WriteString(elems[0])
|
|
302
|
+
for _, s := range elems[1:] {
|
|
303
|
+
b.WriteString(sep)
|
|
304
|
+
b.WriteString(s)
|
|
305
|
+
}
|
|
306
|
+
return b.String()
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Repeat returns a new string consisting of count copies of the string s.
|
|
310
|
+
//
|
|
311
|
+
// It panics if count is negative.
|
|
312
|
+
//
|
|
313
|
+
//gofront:native strings.Repeat
|
|
314
|
+
func Repeat(s string, count int) string {
|
|
315
|
+
if count < 0 {
|
|
316
|
+
panic("strings: negative Repeat count")
|
|
317
|
+
}
|
|
318
|
+
var b Builder
|
|
319
|
+
for i := 0; i < count; i++ {
|
|
320
|
+
b.WriteString(s)
|
|
321
|
+
}
|
|
322
|
+
return b.String()
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Replace returns a copy of the string s with the first n
|
|
326
|
+
// non-overlapping instances of old replaced by new.
|
|
327
|
+
// If old is empty, it matches at the beginning of the string
|
|
328
|
+
// and after each UTF-8 sequence, yielding up to k+1 replacements
|
|
329
|
+
// for a k-rune string.
|
|
330
|
+
// If n < 0, there is no limit on the number of replacements.
|
|
331
|
+
//
|
|
332
|
+
//gofront:native strings.Replace
|
|
333
|
+
func Replace(s, old, new string, n int) string {
|
|
334
|
+
if old == new || n == 0 {
|
|
335
|
+
return s
|
|
336
|
+
}
|
|
337
|
+
if m := Count(s, old); m == 0 {
|
|
338
|
+
return s
|
|
339
|
+
} else if n < 0 || m < n {
|
|
340
|
+
n = m
|
|
341
|
+
}
|
|
342
|
+
var b Builder
|
|
343
|
+
start := 0
|
|
344
|
+
for i := 0; i < n; i++ {
|
|
345
|
+
j := start
|
|
346
|
+
if len(old) == 0 {
|
|
347
|
+
if i > 0 {
|
|
348
|
+
_, wid := utf8.DecodeRuneInString(s[start:])
|
|
349
|
+
j += wid
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
j += Index(s[start:], old)
|
|
353
|
+
}
|
|
354
|
+
b.WriteString(s[start:j])
|
|
355
|
+
b.WriteString(new)
|
|
356
|
+
start = j + len(old)
|
|
357
|
+
}
|
|
358
|
+
b.WriteString(s[start:])
|
|
359
|
+
return b.String()
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// ReplaceAll returns a copy of the string s with all
|
|
363
|
+
// non-overlapping instances of old replaced by new.
|
|
364
|
+
// If old is empty, it matches at the beginning of the string
|
|
365
|
+
// and after each UTF-8 sequence, yielding up to k+1 replacements
|
|
366
|
+
// for a k-rune string.
|
|
367
|
+
//
|
|
368
|
+
//gofront:native strings.ReplaceAll
|
|
369
|
+
func ReplaceAll(s, old, new string) string {
|
|
370
|
+
return Replace(s, old, new, -1)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Cut slices s around the first instance of sep,
|
|
374
|
+
// returning the text before and after sep.
|
|
375
|
+
// The found result reports whether sep appears in s.
|
|
376
|
+
// If sep does not appear in s, cut returns s, "", false.
|
|
377
|
+
func Cut(s, sep string) (before, after string, found bool) {
|
|
378
|
+
if i := Index(s, sep); i >= 0 {
|
|
379
|
+
return s[:i], s[i+len(sep):], true
|
|
380
|
+
}
|
|
381
|
+
return s, "", false
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// CutPrefix returns s without the provided leading prefix string
|
|
385
|
+
// and reports whether it found the prefix.
|
|
386
|
+
// If s doesn't start with prefix, CutPrefix returns s, false.
|
|
387
|
+
// If prefix is the empty string, CutPrefix returns s, true.
|
|
388
|
+
func CutPrefix(s, prefix string) (after string, found bool) {
|
|
389
|
+
if !HasPrefix(s, prefix) {
|
|
390
|
+
return s, false
|
|
391
|
+
}
|
|
392
|
+
return s[len(prefix):], true
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// CutSuffix returns s without the provided ending suffix string
|
|
396
|
+
// and reports whether it found the suffix.
|
|
397
|
+
// If s doesn't end with suffix, CutSuffix returns s, false.
|
|
398
|
+
// If suffix is the empty string, CutSuffix returns s, true.
|
|
399
|
+
func CutSuffix(s, suffix string) (before string, found bool) {
|
|
400
|
+
if !HasSuffix(s, suffix) {
|
|
401
|
+
return s, false
|
|
402
|
+
}
|
|
403
|
+
return s[:len(s)-len(suffix)], true
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Fields splits the string s around each instance of one or more
|
|
407
|
+
// consecutive white space characters, as defined by unicode.IsSpace,
|
|
408
|
+
// returning a slice of substrings of s or an empty slice if s contains only
|
|
409
|
+
// white space.
|
|
410
|
+
//
|
|
411
|
+
//gofront:native strings.Fields
|
|
412
|
+
func Fields(s string) []string {
|
|
413
|
+
return FieldsFunc(s, isSpace)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// FieldsFunc splits the string s at each run of Unicode code points c
|
|
417
|
+
// satisfying f(c) and returns an array of slices of s. If all code points
|
|
418
|
+
// in s satisfy f(c) or the string is empty, an empty slice is returned.
|
|
419
|
+
func FieldsFunc(s string, f func(rune) bool) []string {
|
|
420
|
+
fields := make([]string, 0, 8)
|
|
421
|
+
start := -1
|
|
422
|
+
for i := 0; i < len(s); {
|
|
423
|
+
r, size := utf8.DecodeRuneInString(s[i:])
|
|
424
|
+
if f(r) {
|
|
425
|
+
if start >= 0 {
|
|
426
|
+
fields = append(fields, s[start:i])
|
|
427
|
+
start = -1
|
|
428
|
+
}
|
|
429
|
+
} else if start < 0 {
|
|
430
|
+
start = i
|
|
431
|
+
}
|
|
432
|
+
i += size
|
|
433
|
+
}
|
|
434
|
+
if start >= 0 {
|
|
435
|
+
fields = append(fields, s[start:])
|
|
436
|
+
}
|
|
437
|
+
return fields
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ── Case mapping, folding and mapping ─────────────────────────
|
|
441
|
+
|
|
442
|
+
// Map returns a copy of the string s with all its characters modified
|
|
443
|
+
// according to the mapping function. If mapping returns a negative value, the
|
|
444
|
+
// character is dropped from the string with no replacement.
|
|
445
|
+
func Map(mapping func(rune) rune, s string) string {
|
|
446
|
+
var b Builder
|
|
447
|
+
for _, c := range s {
|
|
448
|
+
r := mapping(c)
|
|
449
|
+
if r >= 0 {
|
|
450
|
+
b.WriteRune(r)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return b.String()
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ToUpper returns s with all Unicode letters mapped to their upper case.
|
|
457
|
+
//
|
|
458
|
+
//gofront:native strings.ToUpper
|
|
459
|
+
func ToUpper(s string) string { return Map(upperRune, s) }
|
|
460
|
+
|
|
461
|
+
// ToLower returns s with all Unicode letters mapped to their lower case.
|
|
462
|
+
//
|
|
463
|
+
//gofront:native strings.ToLower
|
|
464
|
+
func ToLower(s string) string { return Map(lowerRune, s) }
|
|
465
|
+
|
|
466
|
+
// ToTitle returns a copy of the string s with all Unicode letters mapped to
|
|
467
|
+
// their Unicode title case.
|
|
468
|
+
func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
|
|
469
|
+
|
|
470
|
+
// isSeparator reports whether the rune could mark a word boundary.
|
|
471
|
+
func isSeparator(r rune) bool {
|
|
472
|
+
if r <= 0x7F {
|
|
473
|
+
switch {
|
|
474
|
+
case '0' <= r && r <= '9':
|
|
475
|
+
return false
|
|
476
|
+
case 'a' <= r && r <= 'z':
|
|
477
|
+
return false
|
|
478
|
+
case 'A' <= r && r <= 'Z':
|
|
479
|
+
return false
|
|
480
|
+
case r == '_':
|
|
481
|
+
return false
|
|
482
|
+
}
|
|
483
|
+
return true
|
|
484
|
+
}
|
|
485
|
+
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
|
486
|
+
return false
|
|
487
|
+
}
|
|
488
|
+
return unicode.IsSpace(r)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Title returns a copy of the string s with all Unicode letters that begin
|
|
492
|
+
// words mapped to their Unicode title case.
|
|
493
|
+
//
|
|
494
|
+
// Deprecated: The rule Title uses for word boundaries does not handle Unicode
|
|
495
|
+
// punctuation properly.
|
|
496
|
+
func Title(s string) string {
|
|
497
|
+
prev := rune(' ')
|
|
498
|
+
return Map(
|
|
499
|
+
func(r rune) rune {
|
|
500
|
+
if isSeparator(prev) {
|
|
501
|
+
prev = r
|
|
502
|
+
return unicode.ToTitle(r)
|
|
503
|
+
}
|
|
504
|
+
prev = r
|
|
505
|
+
return r
|
|
506
|
+
},
|
|
507
|
+
s)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// EqualFold reports whether s and t, interpreted as UTF-8 strings,
|
|
511
|
+
// are equal under simple Unicode case-folding, which is a more general
|
|
512
|
+
// form of case-insensitivity.
|
|
513
|
+
func EqualFold(s, t string) bool {
|
|
514
|
+
for len(s) != 0 && len(t) != 0 {
|
|
515
|
+
sr, ssize := utf8.DecodeRuneInString(s)
|
|
516
|
+
tr, tsize := utf8.DecodeRuneInString(t)
|
|
517
|
+
s, t = s[ssize:], t[tsize:]
|
|
518
|
+
if tr == sr {
|
|
519
|
+
continue
|
|
520
|
+
}
|
|
521
|
+
if tr < sr {
|
|
522
|
+
tr, sr = sr, tr
|
|
523
|
+
}
|
|
524
|
+
if tr < 0x80 {
|
|
525
|
+
if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' {
|
|
526
|
+
continue
|
|
527
|
+
}
|
|
528
|
+
return false
|
|
529
|
+
}
|
|
530
|
+
r := unicode.SimpleFold(sr)
|
|
531
|
+
for r != sr && r < tr {
|
|
532
|
+
r = unicode.SimpleFold(r)
|
|
533
|
+
}
|
|
534
|
+
if r == tr {
|
|
535
|
+
continue
|
|
536
|
+
}
|
|
537
|
+
return false
|
|
538
|
+
}
|
|
539
|
+
return len(s) == len(t)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// ToValidUTF8 returns a copy of the string s with each run of invalid UTF-8
|
|
543
|
+
// byte sequences replaced by the replacement string, which may be empty.
|
|
544
|
+
// A lone surrogate is the invalid sequence a GoFront string can hold.
|
|
545
|
+
func ToValidUTF8(s, replacement string) string {
|
|
546
|
+
var b Builder
|
|
547
|
+
invalid := false
|
|
548
|
+
for i := 0; i < len(s); {
|
|
549
|
+
_, size := utf8.DecodeRuneInString(s[i:])
|
|
550
|
+
if size == 1 && int(s[i]) >= 0xD800 && int(s[i]) <= 0xDFFF {
|
|
551
|
+
if !invalid {
|
|
552
|
+
invalid = true
|
|
553
|
+
b.WriteString(replacement)
|
|
554
|
+
}
|
|
555
|
+
i += size
|
|
556
|
+
continue
|
|
557
|
+
}
|
|
558
|
+
invalid = false
|
|
559
|
+
b.WriteString(s[i : i+size])
|
|
560
|
+
i += size
|
|
561
|
+
}
|
|
562
|
+
return b.String()
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// ── Trim ──────────────────────────────────────────────────────
|
|
566
|
+
|
|
567
|
+
// IndexFunc returns the index into s of the first Unicode
|
|
568
|
+
// code point satisfying f(c), or -1 if none do.
|
|
569
|
+
func IndexFunc(s string, f func(rune) bool) int {
|
|
570
|
+
return indexFunc(s, f, true)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// LastIndexFunc returns the index into s of the last
|
|
574
|
+
// Unicode code point satisfying f(c), or -1 if none do.
|
|
575
|
+
func LastIndexFunc(s string, f func(rune) bool) int {
|
|
576
|
+
return lastIndexFunc(s, f, true)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
func indexFunc(s string, f func(rune) bool, truth bool) int {
|
|
580
|
+
for i := 0; i < len(s); {
|
|
581
|
+
r, size := utf8.DecodeRuneInString(s[i:])
|
|
582
|
+
if f(r) == truth {
|
|
583
|
+
return i
|
|
584
|
+
}
|
|
585
|
+
i += size
|
|
586
|
+
}
|
|
587
|
+
return -1
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
|
|
591
|
+
for i := len(s); i > 0; {
|
|
592
|
+
r, size := utf8.DecodeLastRuneInString(s[:i])
|
|
593
|
+
i -= size
|
|
594
|
+
if f(r) == truth {
|
|
595
|
+
return i
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return -1
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// inCutset reports whether r is one of the code points of cutset.
|
|
602
|
+
func inCutset(cutset string, r rune) bool {
|
|
603
|
+
for _, c := range cutset {
|
|
604
|
+
if c == r {
|
|
605
|
+
return true
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return false
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Trim returns a slice of the string s with all leading and
|
|
612
|
+
// trailing Unicode code points contained in cutset removed.
|
|
613
|
+
//
|
|
614
|
+
//gofront:native strings.Trim
|
|
615
|
+
func Trim(s, cutset string) string {
|
|
616
|
+
if s == "" || cutset == "" {
|
|
617
|
+
return s
|
|
618
|
+
}
|
|
619
|
+
in := func(r rune) bool { return inCutset(cutset, r) }
|
|
620
|
+
return TrimFunc(s, in)
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// TrimLeft returns a slice of the string s with all leading
|
|
624
|
+
// Unicode code points contained in cutset removed.
|
|
625
|
+
//
|
|
626
|
+
// To remove a prefix, use TrimPrefix instead.
|
|
627
|
+
//
|
|
628
|
+
//gofront:native strings.TrimLeft
|
|
629
|
+
func TrimLeft(s, cutset string) string {
|
|
630
|
+
if s == "" || cutset == "" {
|
|
631
|
+
return s
|
|
632
|
+
}
|
|
633
|
+
return TrimLeftFunc(s, func(r rune) bool { return inCutset(cutset, r) })
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// TrimRight returns a slice of the string s, with all trailing
|
|
637
|
+
// Unicode code points contained in cutset removed.
|
|
638
|
+
//
|
|
639
|
+
// To remove a suffix, use TrimSuffix instead.
|
|
640
|
+
//
|
|
641
|
+
//gofront:native strings.TrimRight
|
|
642
|
+
func TrimRight(s, cutset string) string {
|
|
643
|
+
if s == "" || cutset == "" {
|
|
644
|
+
return s
|
|
645
|
+
}
|
|
646
|
+
return TrimRightFunc(s, func(r rune) bool { return inCutset(cutset, r) })
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// TrimFunc returns a slice of the string s with all leading
|
|
650
|
+
// and trailing Unicode code points c satisfying f(c) removed.
|
|
651
|
+
func TrimFunc(s string, f func(rune) bool) string {
|
|
652
|
+
return TrimRightFunc(TrimLeftFunc(s, f), f)
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// TrimLeftFunc returns a slice of the string s with all leading
|
|
656
|
+
// Unicode code points c satisfying f(c) removed.
|
|
657
|
+
func TrimLeftFunc(s string, f func(rune) bool) string {
|
|
658
|
+
i := indexFunc(s, f, false)
|
|
659
|
+
if i == -1 {
|
|
660
|
+
return ""
|
|
661
|
+
}
|
|
662
|
+
return s[i:]
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// TrimRightFunc returns a slice of the string s with all trailing
|
|
666
|
+
// Unicode code points c satisfying f(c) removed.
|
|
667
|
+
func TrimRightFunc(s string, f func(rune) bool) string {
|
|
668
|
+
i := lastIndexFunc(s, f, false)
|
|
669
|
+
if i >= 0 {
|
|
670
|
+
_, wid := utf8.DecodeRuneInString(s[i:])
|
|
671
|
+
i += wid
|
|
672
|
+
} else {
|
|
673
|
+
i++
|
|
674
|
+
}
|
|
675
|
+
return s[0:i]
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// TrimSpace returns a slice of the string s, with all leading
|
|
679
|
+
// and trailing white space removed, as defined by Unicode.
|
|
680
|
+
//
|
|
681
|
+
//gofront:native strings.TrimSpace
|
|
682
|
+
func TrimSpace(s string) string { return TrimFunc(s, isSpace) }
|
|
683
|
+
|
|
684
|
+
// TrimPrefix returns s without the provided leading prefix string.
|
|
685
|
+
// If s doesn't start with prefix, s is returned unchanged.
|
|
686
|
+
//
|
|
687
|
+
//gofront:native strings.TrimPrefix
|
|
688
|
+
func TrimPrefix(s, prefix string) string {
|
|
689
|
+
if HasPrefix(s, prefix) {
|
|
690
|
+
return s[len(prefix):]
|
|
691
|
+
}
|
|
692
|
+
return s
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// TrimSuffix returns s without the provided trailing suffix string.
|
|
696
|
+
// If s doesn't end with suffix, s is returned unchanged.
|
|
697
|
+
//
|
|
698
|
+
//gofront:native strings.TrimSuffix
|
|
699
|
+
func TrimSuffix(s, suffix string) string {
|
|
700
|
+
if HasSuffix(s, suffix) {
|
|
701
|
+
return s[:len(s)-len(suffix)]
|
|
702
|
+
}
|
|
703
|
+
return s
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// ── Iterators ─────────────────────────────────────────────────
|
|
707
|
+
|
|
708
|
+
// Lines returns an iterator over the newline-terminated lines in the string s.
|
|
709
|
+
// The lines yielded by the iterator include their terminating newlines.
|
|
710
|
+
// If s is empty, the iterator yields no lines at all.
|
|
711
|
+
// If s does not end in a newline, the final yielded line will not end in a newline.
|
|
712
|
+
func Lines(s string) iter.Seq[string] {
|
|
713
|
+
return func(yield func(string) bool) {
|
|
714
|
+
for len(s) > 0 {
|
|
715
|
+
var line string
|
|
716
|
+
if i := IndexByte(s, '\n'); i >= 0 {
|
|
717
|
+
line, s = s[:i+1], s[i+1:]
|
|
718
|
+
} else {
|
|
719
|
+
line, s = s, ""
|
|
720
|
+
}
|
|
721
|
+
if !yield(line) {
|
|
722
|
+
return
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// explodeSeq returns an iterator over the runes in s.
|
|
729
|
+
func explodeSeq(s string) iter.Seq[string] {
|
|
730
|
+
return func(yield func(string) bool) {
|
|
731
|
+
for _, r := range []rune(s) {
|
|
732
|
+
if !yield(string(r)) {
|
|
733
|
+
return
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// splitSeq is SplitSeq or SplitAfterSeq, configured by how many
|
|
740
|
+
// units of sep to include in the results (none or all).
|
|
741
|
+
func splitSeq(s, sep string, sepSave int) iter.Seq[string] {
|
|
742
|
+
if len(sep) == 0 {
|
|
743
|
+
return explodeSeq(s)
|
|
744
|
+
}
|
|
745
|
+
return func(yield func(string) bool) {
|
|
746
|
+
for {
|
|
747
|
+
i := Index(s, sep)
|
|
748
|
+
if i < 0 {
|
|
749
|
+
break
|
|
750
|
+
}
|
|
751
|
+
frag := s[:i+sepSave]
|
|
752
|
+
if !yield(frag) {
|
|
753
|
+
return
|
|
754
|
+
}
|
|
755
|
+
s = s[i+len(sep):]
|
|
756
|
+
}
|
|
757
|
+
yield(s)
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// SplitSeq returns an iterator over substrings of s split by sep.
|
|
762
|
+
// The iterator yields the same strings that would be returned by Split(s, sep),
|
|
763
|
+
// but without constructing the slice.
|
|
764
|
+
func SplitSeq(s, sep string) iter.Seq[string] {
|
|
765
|
+
return splitSeq(s, sep, 0)
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep.
|
|
769
|
+
// The iterator yields the same strings that would be returned by SplitAfter(s, sep),
|
|
770
|
+
// but without constructing the slice.
|
|
771
|
+
func SplitAfterSeq(s, sep string) iter.Seq[string] {
|
|
772
|
+
return splitSeq(s, sep, len(sep))
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// FieldsSeq returns an iterator over substrings of s split around runs of
|
|
776
|
+
// whitespace characters, as defined by unicode.IsSpace.
|
|
777
|
+
// The iterator yields the same strings that would be returned by Fields(s),
|
|
778
|
+
// but without constructing the slice.
|
|
779
|
+
func FieldsSeq(s string) iter.Seq[string] {
|
|
780
|
+
return FieldsFuncSeq(s, isSpace)
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// FieldsFuncSeq returns an iterator over substrings of s split around runs of
|
|
784
|
+
// Unicode code points satisfying f(c).
|
|
785
|
+
// The iterator yields the same strings that would be returned by FieldsFunc(s),
|
|
786
|
+
// but without constructing the slice.
|
|
787
|
+
func FieldsFuncSeq(s string, f func(rune) bool) iter.Seq[string] {
|
|
788
|
+
return func(yield func(string) bool) {
|
|
789
|
+
runes := []rune(s)
|
|
790
|
+
start := -1
|
|
791
|
+
for i, r := range runes {
|
|
792
|
+
if f(r) {
|
|
793
|
+
if start >= 0 {
|
|
794
|
+
if !yield(string(runes[start:i])) {
|
|
795
|
+
return
|
|
796
|
+
}
|
|
797
|
+
start = -1
|
|
798
|
+
}
|
|
799
|
+
} else if start < 0 {
|
|
800
|
+
start = i
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if start >= 0 {
|
|
804
|
+
yield(string(runes[start:]))
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|