Source file src/pkg/strings/strings.go
1
2
3
4
5
6 package strings
7
8 import (
9 "unicode"
10 "unicode/utf8"
11 )
12
13
14
15 func explode(s string, n int) []string {
16 if n == 0 {
17 return nil
18 }
19 l := utf8.RuneCountInString(s)
20 if n <= 0 || n > l {
21 n = l
22 }
23 a := make([]string, n)
24 var size int
25 var ch rune
26 i, cur := 0, 0
27 for ; i+1 < n; i++ {
28 ch, size = utf8.DecodeRuneInString(s[cur:])
29 if ch == utf8.RuneError {
30 a[i] = string(utf8.RuneError)
31 } else {
32 a[i] = s[cur : cur+size]
33 }
34 cur += size
35 }
36
37 if cur < len(s) {
38 a[i] = s[cur:]
39 }
40 return a
41 }
42
43
44 const primeRK = 16777619
45
46
47
48 func hashstr(sep string) (uint32, uint32) {
49 hash := uint32(0)
50 for i := 0; i < len(sep); i++ {
51 hash = hash*primeRK + uint32(sep[i])
52
53 }
54 var pow, sq uint32 = 1, primeRK
55 for i := len(sep); i > 0; i >>= 1 {
56 if i&1 != 0 {
57 pow *= sq
58 }
59 sq *= sq
60 }
61 return hash, pow
62 }
63
64
65 func Count(s, sep string) int {
66 n := 0
67
68 switch {
69 case len(sep) == 0:
70 return utf8.RuneCountInString(s) + 1
71 case len(sep) == 1:
72
73 c := sep[0]
74 for i := 0; i < len(s); i++ {
75 if s[i] == c {
76 n++
77 }
78 }
79 return n
80 case len(sep) > len(s):
81 return 0
82 case len(sep) == len(s):
83 if sep == s {
84 return 1
85 }
86 return 0
87 }
88 hashsep, pow := hashstr(sep)
89 h := uint32(0)
90 for i := 0; i < len(sep); i++ {
91 h = h*primeRK + uint32(s[i])
92 }
93 lastmatch := 0
94 if h == hashsep && s[:len(sep)] == sep {
95 n++
96 lastmatch = len(sep)
97 }
98 for i := len(sep); i < len(s); {
99 h *= primeRK
100 h += uint32(s[i])
101 h -= pow * uint32(s[i-len(sep)])
102 i++
103 if h == hashsep && lastmatch <= i-len(sep) && s[i-len(sep):i] == sep {
104 n++
105 lastmatch = i
106 }
107 }
108 return n
109 }
110
111
112 func Contains(s, substr string) bool {
113 return Index(s, substr) >= 0
114 }
115
116
117 func ContainsAny(s, chars string) bool {
118 return IndexAny(s, chars) >= 0
119 }
120
121
122 func ContainsRune(s string, r rune) bool {
123 return IndexRune(s, r) >= 0
124 }
125
126
127 func Index(s, sep string) int {
128 n := len(sep)
129 switch {
130 case n == 0:
131 return 0
132 case n == 1:
133 c := sep[0]
134
135 for i := 0; i < len(s); i++ {
136 if s[i] == c {
137 return i
138 }
139 }
140 return -1
141 case n == len(s):
142 if sep == s {
143 return 0
144 }
145 return -1
146 case n > len(s):
147 return -1
148 }
149
150 hashsep, pow := hashstr(sep)
151 var h uint32
152 for i := 0; i < n; i++ {
153 h = h*primeRK + uint32(s[i])
154 }
155 if h == hashsep && s[:n] == sep {
156 return 0
157 }
158 for i := n; i < len(s); {
159 h *= primeRK
160 h += uint32(s[i])
161 h -= pow * uint32(s[i-n])
162 i++
163 if h == hashsep && s[i-n:i] == sep {
164 return i - n
165 }
166 }
167 return -1
168 }
169
170
171 func LastIndex(s, sep string) int {
172 n := len(sep)
173 if n == 0 {
174 return len(s)
175 }
176 c := sep[0]
177 if n == 1 {
178
179 for i := len(s) - 1; i >= 0; i-- {
180 if s[i] == c {
181 return i
182 }
183 }
184 return -1
185 }
186
187 for i := len(s) - n; i >= 0; i-- {
188 if s[i] == c && s[i:i+n] == sep {
189 return i
190 }
191 }
192 return -1
193 }
194
195
196
197 func IndexRune(s string, r rune) int {
198 switch {
199 case r < 0x80:
200 b := byte(r)
201 for i := 0; i < len(s); i++ {
202 if s[i] == b {
203 return i
204 }
205 }
206 default:
207 for i, c := range s {
208 if c == r {
209 return i
210 }
211 }
212 }
213 return -1
214 }
215
216
217
218 func IndexAny(s, chars string) int {
219 if len(chars) > 0 {
220 for i, c := range s {
221 for _, m := range chars {
222 if c == m {
223 return i
224 }
225 }
226 }
227 }
228 return -1
229 }
230
231
232
233
234 func LastIndexAny(s, chars string) int {
235 if len(chars) > 0 {
236 for i := len(s); i > 0; {
237 rune, size := utf8.DecodeLastRuneInString(s[0:i])
238 i -= size
239 for _, m := range chars {
240 if rune == m {
241 return i
242 }
243 }
244 }
245 }
246 return -1
247 }
248
249
250
251 func genSplit(s, sep string, sepSave, n int) []string {
252 if n == 0 {
253 return nil
254 }
255 if sep == "" {
256 return explode(s, n)
257 }
258 if n < 0 {
259 n = Count(s, sep) + 1
260 }
261 c := sep[0]
262 start := 0
263 a := make([]string, n)
264 na := 0
265 for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
266 if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
267 a[na] = s[start : i+sepSave]
268 na++
269 start = i + len(sep)
270 i += len(sep) - 1
271 }
272 }
273 a[na] = s[start:]
274 return a[0 : na+1]
275 }
276
277
278
279
280
281
282
283
284 func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
285
286
287
288
289
290
291
292
293 func SplitAfterN(s, sep string, n int) []string {
294 return genSplit(s, sep, len(sep), n)
295 }
296
297
298
299
300
301 func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
302
303
304
305
306
307 func SplitAfter(s, sep string) []string {
308 return genSplit(s, sep, len(sep), -1)
309 }
310
311
312
313
314 func Fields(s string) []string {
315 return FieldsFunc(s, unicode.IsSpace)
316 }
317
318
319
320
321 func FieldsFunc(s string, f func(rune) bool) []string {
322
323 n := 0
324 inField := false
325 for _, rune := range s {
326 wasInField := inField
327 inField = !f(rune)
328 if inField && !wasInField {
329 n++
330 }
331 }
332
333
334 a := make([]string, n)
335 na := 0
336 fieldStart := -1
337 for i, rune := range s {
338 if f(rune) {
339 if fieldStart >= 0 {
340 a[na] = s[fieldStart:i]
341 na++
342 fieldStart = -1
343 }
344 } else if fieldStart == -1 {
345 fieldStart = i
346 }
347 }
348 if fieldStart >= 0 {
349 a[na] = s[fieldStart:]
350 }
351 return a
352 }
353
354
355
356 func Join(a []string, sep string) string {
357 if len(a) == 0 {
358 return ""
359 }
360 if len(a) == 1 {
361 return a[0]
362 }
363 n := len(sep) * (len(a) - 1)
364 for i := 0; i < len(a); i++ {
365 n += len(a[i])
366 }
367
368 b := make([]byte, n)
369 bp := copy(b, a[0])
370 for _, s := range a[1:] {
371 bp += copy(b[bp:], sep)
372 bp += copy(b[bp:], s)
373 }
374 return string(b)
375 }
376
377
378 func HasPrefix(s, prefix string) bool {
379 return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
380 }
381
382
383 func HasSuffix(s, suffix string) bool {
384 return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
385 }
386
387
388
389
390 func Map(mapping func(rune) rune, s string) string {
391
392
393
394 maxbytes := len(s)
395 nbytes := 0
396
397
398 var b []byte
399
400 for i, c := range s {
401 r := mapping(c)
402 if b == nil {
403 if r == c {
404 continue
405 }
406 b = make([]byte, maxbytes)
407 nbytes = copy(b, s[:i])
408 }
409 if r >= 0 {
410 wid := 1
411 if r >= utf8.RuneSelf {
412 wid = utf8.RuneLen(r)
413 }
414 if nbytes+wid > maxbytes {
415
416 maxbytes = maxbytes*2 + utf8.UTFMax
417 nb := make([]byte, maxbytes)
418 copy(nb, b[0:nbytes])
419 b = nb
420 }
421 nbytes += utf8.EncodeRune(b[nbytes:maxbytes], r)
422 }
423 }
424 if b == nil {
425 return s
426 }
427 return string(b[0:nbytes])
428 }
429
430
431 func Repeat(s string, count int) string {
432 b := make([]byte, len(s)*count)
433 bp := 0
434 for i := 0; i < count; i++ {
435 for j := 0; j < len(s); j++ {
436 b[bp] = s[j]
437 bp++
438 }
439 }
440 return string(b)
441 }
442
443
444 func ToUpper(s string) string { return Map(unicode.ToUpper, s) }
445
446
447 func ToLower(s string) string { return Map(unicode.ToLower, s) }
448
449
450 func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
451
452
453
454 func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
455 return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
456 }
457
458
459
460 func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
461 return Map(func(r rune) rune { return _case.ToLower(r) }, s)
462 }
463
464
465
466 func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
467 return Map(func(r rune) rune { return _case.ToTitle(r) }, s)
468 }
469
470
471
472 func isSeparator(r rune) bool {
473
474 if r <= 0x7F {
475 switch {
476 case '0' <= r && r <= '9':
477 return false
478 case 'a' <= r && r <= 'z':
479 return false
480 case 'A' <= r && r <= 'Z':
481 return false
482 case r == '_':
483 return false
484 }
485 return true
486 }
487
488 if unicode.IsLetter(r) || unicode.IsDigit(r) {
489 return false
490 }
491
492 return unicode.IsSpace(r)
493 }
494
495
496
497
498
499 func Title(s string) string {
500
501
502
503 prev := ' '
504 return Map(
505 func(r rune) rune {
506 if isSeparator(prev) {
507 prev = r
508 return unicode.ToTitle(r)
509 }
510 prev = r
511 return r
512 },
513 s)
514 }
515
516
517
518 func TrimLeftFunc(s string, f func(rune) bool) string {
519 i := indexFunc(s, f, false)
520 if i == -1 {
521 return ""
522 }
523 return s[i:]
524 }
525
526
527
528 func TrimRightFunc(s string, f func(rune) bool) string {
529 i := lastIndexFunc(s, f, false)
530 if i >= 0 && s[i] >= utf8.RuneSelf {
531 _, wid := utf8.DecodeRuneInString(s[i:])
532 i += wid
533 } else {
534 i++
535 }
536 return s[0:i]
537 }
538
539
540
541 func TrimFunc(s string, f func(rune) bool) string {
542 return TrimRightFunc(TrimLeftFunc(s, f), f)
543 }
544
545
546
547 func IndexFunc(s string, f func(rune) bool) int {
548 return indexFunc(s, f, true)
549 }
550
551
552
553 func LastIndexFunc(s string, f func(rune) bool) int {
554 return lastIndexFunc(s, f, true)
555 }
556
557
558
559
560 func indexFunc(s string, f func(rune) bool, truth bool) int {
561 start := 0
562 for start < len(s) {
563 wid := 1
564 r := rune(s[start])
565 if r >= utf8.RuneSelf {
566 r, wid = utf8.DecodeRuneInString(s[start:])
567 }
568 if f(r) == truth {
569 return start
570 }
571 start += wid
572 }
573 return -1
574 }
575
576
577
578
579 func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
580 for i := len(s); i > 0; {
581 r, size := utf8.DecodeLastRuneInString(s[0:i])
582 i -= size
583 if f(r) == truth {
584 return i
585 }
586 }
587 return -1
588 }
589
590 func makeCutsetFunc(cutset string) func(rune) bool {
591 return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
592 }
593
594
595
596 func Trim(s string, cutset string) string {
597 if s == "" || cutset == "" {
598 return s
599 }
600 return TrimFunc(s, makeCutsetFunc(cutset))
601 }
602
603
604
605 func TrimLeft(s string, cutset string) string {
606 if s == "" || cutset == "" {
607 return s
608 }
609 return TrimLeftFunc(s, makeCutsetFunc(cutset))
610 }
611
612
613
614 func TrimRight(s string, cutset string) string {
615 if s == "" || cutset == "" {
616 return s
617 }
618 return TrimRightFunc(s, makeCutsetFunc(cutset))
619 }
620
621
622
623 func TrimSpace(s string) string {
624 return TrimFunc(s, unicode.IsSpace)
625 }
626
627
628
629 func TrimPrefix(s, prefix string) string {
630 if HasPrefix(s, prefix) {
631 return s[len(prefix):]
632 }
633 return s
634 }
635
636
637
638 func TrimSuffix(s, suffix string) string {
639 if HasSuffix(s, suffix) {
640 return s[:len(s)-len(suffix)]
641 }
642 return s
643 }
644
645
646
647
648 func Replace(s, old, new string, n int) string {
649 if old == new || n == 0 {
650 return s
651 }
652
653
654 if m := Count(s, old); m == 0 {
655 return s
656 } else if n < 0 || m < n {
657 n = m
658 }
659
660
661 t := make([]byte, len(s)+n*(len(new)-len(old)))
662 w := 0
663 start := 0
664 for i := 0; i < n; i++ {
665 j := start
666 if len(old) == 0 {
667 if i > 0 {
668 _, wid := utf8.DecodeRuneInString(s[start:])
669 j += wid
670 }
671 } else {
672 j += Index(s[start:], old)
673 }
674 w += copy(t[w:], s[start:j])
675 w += copy(t[w:], new)
676 start = j + len(old)
677 }
678 w += copy(t[w:], s[start:])
679 return string(t[0:w])
680 }
681
682
683
684 func EqualFold(s, t string) bool {
685 for s != "" && t != "" {
686
687 var sr, tr rune
688 if s[0] < utf8.RuneSelf {
689 sr, s = rune(s[0]), s[1:]
690 } else {
691 r, size := utf8.DecodeRuneInString(s)
692 sr, s = r, s[size:]
693 }
694 if t[0] < utf8.RuneSelf {
695 tr, t = rune(t[0]), t[1:]
696 } else {
697 r, size := utf8.DecodeRuneInString(t)
698 tr, t = r, t[size:]
699 }
700
701
702
703
704 if tr == sr {
705 continue
706 }
707
708
709 if tr < sr {
710 tr, sr = sr, tr
711 }
712
713 if tr < utf8.RuneSelf && 'A' <= sr && sr <= 'Z' {
714
715 if tr == sr+'a'-'A' {
716 continue
717 }
718 return false
719 }
720
721
722
723 r := unicode.SimpleFold(sr)
724 for r != sr && r < tr {
725 r = unicode.SimpleFold(r)
726 }
727 if r == tr {
728 continue
729 }
730 return false
731 }
732
733
734 return s == t
735 }
View as plain text