Source file
src/strings/strings.go
1
2
3
4
5
6
7
8 package strings
9
10 import (
11 "internal/bytealg"
12 "internal/stringslite"
13 "math/bits"
14 "unicode"
15 "unicode/utf8"
16 )
17
18 const maxInt = int(^uint(0) >> 1)
19
20
21
22
23 func explode(s string, n int) []string {
24 l := utf8.RuneCountInString(s)
25 if n < 0 || n > l {
26 n = l
27 }
28 a := make([]string, n)
29 for i := 0; i < n-1; i++ {
30 _, size := utf8.DecodeRuneInString(s)
31 a[i] = s[:size]
32 s = s[size:]
33 }
34 if n > 0 {
35 a[n-1] = s
36 }
37 return a
38 }
39
40
41
42 func Count(s, substr string) int {
43
44 if len(substr) == 0 {
45 return utf8.RuneCountInString(s) + 1
46 }
47 if len(substr) == 1 {
48 return bytealg.CountString(s, substr[0])
49 }
50 n := 0
51 for {
52 i := Index(s, substr)
53 if i == -1 {
54 return n
55 }
56 n++
57 s = s[i+len(substr):]
58 }
59 }
60
61
62 func Contains(s, substr string) bool {
63 return Index(s, substr) >= 0
64 }
65
66
67 func ContainsAny(s, chars string) bool {
68 return IndexAny(s, chars) >= 0
69 }
70
71
72 func ContainsRune(s string, r rune) bool {
73 return IndexRune(s, r) >= 0
74 }
75
76
77 func ContainsFunc(s string, f func(rune) bool) bool {
78 return IndexFunc(s, f) >= 0
79 }
80
81
82 func LastIndex(s, substr string) int {
83 n := len(substr)
84 switch {
85 case n == 0:
86 return len(s)
87 case n == 1:
88 return bytealg.LastIndexByteString(s, substr[0])
89 case n == len(s):
90 if substr == s {
91 return 0
92 }
93 return -1
94 case n > len(s):
95 return -1
96 }
97 return bytealg.LastIndexRabinKarp(s, substr)
98 }
99
100
101 func IndexByte(s string, c byte) int {
102 return stringslite.IndexByte(s, c)
103 }
104
105
106
107
108
109 func IndexRune(s string, r rune) int {
110 const haveFastIndex = bytealg.MaxBruteForce > 0
111 switch {
112 case 0 <= r && r < utf8.RuneSelf:
113 return IndexByte(s, byte(r))
114 case r == utf8.RuneError:
115 for i, r := range s {
116 if r == utf8.RuneError {
117 return i
118 }
119 }
120 return -1
121 case !utf8.ValidRune(r):
122 return -1
123 default:
124
125
126
127 rs := string(r)
128 last := len(rs) - 1
129 i := last
130 fails := 0
131 for i < len(s) {
132 if s[i] != rs[last] {
133 o := IndexByte(s[i+1:], rs[last])
134 if o < 0 {
135 return -1
136 }
137 i += o + 1
138 }
139
140 for j := 1; j < len(rs); j++ {
141 if s[i-j] != rs[last-j] {
142 goto next
143 }
144 }
145 return i - last
146 next:
147 fails++
148 i++
149 if (haveFastIndex && fails > bytealg.Cutover(i)) && i < len(s) ||
150 (!haveFastIndex && fails >= 4+i>>4 && i < len(s)) {
151 goto fallback
152 }
153 }
154 return -1
155
156 fallback:
157
158 if haveFastIndex {
159 if j := bytealg.IndexString(s[i-last:], string(r)); j >= 0 {
160 return i + j - last
161 }
162 } else {
163 c0 := rs[last]
164 c1 := rs[last-1]
165 loop:
166 for ; i < len(s); i++ {
167 if s[i] == c0 && s[i-1] == c1 {
168 for k := 2; k < len(rs); k++ {
169 if s[i-k] != rs[last-k] {
170 continue loop
171 }
172 }
173 return i - last
174 }
175 }
176 }
177 return -1
178 }
179 }
180
181
182
183 func IndexAny(s, chars string) int {
184 if chars == "" {
185
186 return -1
187 }
188 if len(chars) == 1 {
189
190 r := rune(chars[0])
191 if r >= utf8.RuneSelf {
192 r = utf8.RuneError
193 }
194 return IndexRune(s, r)
195 }
196 if len(s) > 8 {
197 if as, isASCII := makeASCIISet(chars); isASCII {
198 for i := 0; i < len(s); i++ {
199 if as.contains(s[i]) {
200 return i
201 }
202 }
203 return -1
204 }
205 }
206 for i, c := range s {
207 if IndexRune(chars, c) >= 0 {
208 return i
209 }
210 }
211 return -1
212 }
213
214
215
216
217 func LastIndexAny(s, chars string) int {
218 if chars == "" {
219
220 return -1
221 }
222 if len(s) == 1 {
223 rc := rune(s[0])
224 if rc >= utf8.RuneSelf {
225 rc = utf8.RuneError
226 }
227 if IndexRune(chars, rc) >= 0 {
228 return 0
229 }
230 return -1
231 }
232 if len(s) > 8 {
233 if as, isASCII := makeASCIISet(chars); isASCII {
234 for i := len(s) - 1; i >= 0; i-- {
235 if as.contains(s[i]) {
236 return i
237 }
238 }
239 return -1
240 }
241 }
242 if len(chars) == 1 {
243 rc := rune(chars[0])
244 if rc >= utf8.RuneSelf {
245 rc = utf8.RuneError
246 }
247 for i := len(s); i > 0; {
248 r, size := utf8.DecodeLastRuneInString(s[:i])
249 i -= size
250 if rc == r {
251 return i
252 }
253 }
254 return -1
255 }
256 for i := len(s); i > 0; {
257 r, size := utf8.DecodeLastRuneInString(s[:i])
258 i -= size
259 if IndexRune(chars, r) >= 0 {
260 return i
261 }
262 }
263 return -1
264 }
265
266
267 func LastIndexByte(s string, c byte) int {
268 return bytealg.LastIndexByteString(s, c)
269 }
270
271
272
273 func genSplit(s, sep string, sepSave, n int) []string {
274 if n == 0 {
275 return nil
276 }
277 if sep == "" {
278 return explode(s, n)
279 }
280 if n < 0 {
281 n = Count(s, sep) + 1
282 }
283
284 if n > len(s)+1 {
285 n = len(s) + 1
286 }
287 a := make([]string, n)
288 n--
289 i := 0
290 for i < n {
291 m := Index(s, sep)
292 if m < 0 {
293 break
294 }
295 a[i] = s[:m+sepSave]
296 s = s[m+len(sep):]
297 i++
298 }
299 a[i] = s
300 return a[:i+1]
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315 func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
316
317
318
319
320
321
322
323
324
325
326
327 func SplitAfterN(s, sep string, n int) []string {
328 return genSplit(s, sep, len(sep), n)
329 }
330
331
332
333
334
335
336
337
338
339
340
341
342
343 func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
344
345
346
347
348
349
350
351
352
353
354
355 func SplitAfter(s, sep string) []string {
356 return genSplit(s, sep, len(sep), -1)
357 }
358
359 var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
360
361
362
363
364
365
366 func Fields(s string) []string {
367
368
369 n := 0
370 wasSpace := 1
371
372 setBits := uint8(0)
373 for i := 0; i < len(s); i++ {
374 r := s[i]
375 setBits |= r
376 isSpace := int(asciiSpace[r])
377 n += wasSpace & ^isSpace
378 wasSpace = isSpace
379 }
380
381 if setBits >= utf8.RuneSelf {
382
383 return FieldsFunc(s, unicode.IsSpace)
384 }
385
386 a := make([]string, n)
387 na := 0
388 fieldStart := 0
389 i := 0
390
391 for i < len(s) && asciiSpace[s[i]] != 0 {
392 i++
393 }
394 fieldStart = i
395 for i < len(s) {
396 if asciiSpace[s[i]] == 0 {
397 i++
398 continue
399 }
400 a[na] = s[fieldStart:i]
401 na++
402 i++
403
404 for i < len(s) && asciiSpace[s[i]] != 0 {
405 i++
406 }
407 fieldStart = i
408 }
409 if fieldStart < len(s) {
410 a[na] = s[fieldStart:]
411 }
412 return a
413 }
414
415
416
417
418
419
420
421
422
423 func FieldsFunc(s string, f func(rune) bool) []string {
424
425
426 type span struct {
427 start int
428 end int
429 }
430 spans := make([]span, 0, 32)
431
432
433
434
435
436 start := -1
437 for end, rune := range s {
438 if f(rune) {
439 if start >= 0 {
440 spans = append(spans, span{start, end})
441
442
443
444 start = ^start
445 }
446 } else {
447 if start < 0 {
448 start = end
449 }
450 }
451 }
452
453
454 if start >= 0 {
455 spans = append(spans, span{start, len(s)})
456 }
457
458
459 a := make([]string, len(spans))
460 for i, span := range spans {
461 a[i] = s[span.start:span.end]
462 }
463
464 return a
465 }
466
467
468
469 func Join(elems []string, sep string) string {
470 switch len(elems) {
471 case 0:
472 return ""
473 case 1:
474 return elems[0]
475 }
476
477 var n int
478 if len(sep) > 0 {
479 if len(sep) >= maxInt/(len(elems)-1) {
480 panic("strings: Join output length overflow")
481 }
482 n += len(sep) * (len(elems) - 1)
483 }
484 for _, elem := range elems {
485 if len(elem) > maxInt-n {
486 panic("strings: Join output length overflow")
487 }
488 n += len(elem)
489 }
490
491 var b Builder
492 b.Grow(n)
493 b.WriteString(elems[0])
494 for _, s := range elems[1:] {
495 b.WriteString(sep)
496 b.WriteString(s)
497 }
498 return b.String()
499 }
500
501
502 func HasPrefix(s, prefix string) bool {
503 return stringslite.HasPrefix(s, prefix)
504 }
505
506
507 func HasSuffix(s, suffix string) bool {
508 return stringslite.HasSuffix(s, suffix)
509 }
510
511
512
513
514 func Map(mapping func(rune) rune, s string) string {
515
516
517
518
519
520
521 var b Builder
522
523 for i, c := range s {
524 r := mapping(c)
525 if r == c && c != utf8.RuneError {
526 continue
527 }
528
529 var width int
530 if c == utf8.RuneError {
531 c, width = utf8.DecodeRuneInString(s[i:])
532 if width != 1 && r == c {
533 continue
534 }
535 } else {
536 width = utf8.RuneLen(c)
537 }
538
539 b.Grow(len(s) + utf8.UTFMax)
540 b.WriteString(s[:i])
541 if r >= 0 {
542 b.WriteRune(r)
543 }
544
545 s = s[i+width:]
546 break
547 }
548
549
550 if b.Cap() == 0 {
551 return s
552 }
553
554 for _, c := range s {
555 r := mapping(c)
556
557 if r >= 0 {
558
559
560
561 if r < utf8.RuneSelf {
562 b.WriteByte(byte(r))
563 } else {
564
565 b.WriteRune(r)
566 }
567 }
568 }
569
570 return b.String()
571 }
572
573
574
575
576
577 const (
578 repeatedSpaces = "" +
579 " " +
580 " "
581 repeatedDashes = "" +
582 "----------------------------------------------------------------" +
583 "----------------------------------------------------------------"
584 repeatedZeroes = "" +
585 "0000000000000000000000000000000000000000000000000000000000000000"
586 repeatedEquals = "" +
587 "================================================================" +
588 "================================================================"
589 repeatedTabs = "" +
590 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +
591 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
592 )
593
594
595
596
597
598 func Repeat(s string, count int) string {
599 switch count {
600 case 0:
601 return ""
602 case 1:
603 return s
604 }
605
606
607
608
609 if count < 0 {
610 panic("strings: negative Repeat count")
611 }
612 hi, lo := bits.Mul(uint(len(s)), uint(count))
613 if hi > 0 || lo > uint(maxInt) {
614 panic("strings: Repeat output length overflow")
615 }
616 n := int(lo)
617
618 if len(s) == 0 {
619 return ""
620 }
621
622
623 switch s[0] {
624 case ' ', '-', '0', '=', '\t':
625 switch {
626 case n <= len(repeatedSpaces) && HasPrefix(repeatedSpaces, s):
627 return repeatedSpaces[:n]
628 case n <= len(repeatedDashes) && HasPrefix(repeatedDashes, s):
629 return repeatedDashes[:n]
630 case n <= len(repeatedZeroes) && HasPrefix(repeatedZeroes, s):
631 return repeatedZeroes[:n]
632 case n <= len(repeatedEquals) && HasPrefix(repeatedEquals, s):
633 return repeatedEquals[:n]
634 case n <= len(repeatedTabs) && HasPrefix(repeatedTabs, s):
635 return repeatedTabs[:n]
636 }
637 }
638
639
640
641
642
643
644
645
646
647
648
649 const chunkLimit = 8 * 1024
650 chunkMax := n
651 if n > chunkLimit {
652 chunkMax = chunkLimit / len(s) * len(s)
653 if chunkMax == 0 {
654 chunkMax = len(s)
655 }
656 }
657
658 var b Builder
659 b.Grow(n)
660 b.WriteString(s)
661 for b.Len() < n {
662 chunk := min(n-b.Len(), b.Len(), chunkMax)
663 b.WriteString(b.String()[:chunk])
664 }
665 return b.String()
666 }
667
668
669 func ToUpper(s string) string {
670 isASCII, hasLower := true, false
671 for i := 0; i < len(s); i++ {
672 c := s[i]
673 if c >= utf8.RuneSelf {
674 isASCII = false
675 break
676 }
677 hasLower = hasLower || ('a' <= c && c <= 'z')
678 }
679
680 if isASCII {
681 if !hasLower {
682 return s
683 }
684 var (
685 b Builder
686 pos int
687 )
688 b.Grow(len(s))
689 for i := 0; i < len(s); i++ {
690 c := s[i]
691 if 'a' <= c && c <= 'z' {
692 c -= 'a' - 'A'
693 if pos < i {
694 b.WriteString(s[pos:i])
695 }
696 b.WriteByte(c)
697 pos = i + 1
698 }
699 }
700 if pos < len(s) {
701 b.WriteString(s[pos:])
702 }
703 return b.String()
704 }
705 return Map(unicode.ToUpper, s)
706 }
707
708
709 func ToLower(s string) string {
710 isASCII, hasUpper := true, false
711 for i := 0; i < len(s); i++ {
712 c := s[i]
713 if c >= utf8.RuneSelf {
714 isASCII = false
715 break
716 }
717 hasUpper = hasUpper || ('A' <= c && c <= 'Z')
718 }
719
720 if isASCII {
721 if !hasUpper {
722 return s
723 }
724 var (
725 b Builder
726 pos int
727 )
728 b.Grow(len(s))
729 for i := 0; i < len(s); i++ {
730 c := s[i]
731 if 'A' <= c && c <= 'Z' {
732 c += 'a' - 'A'
733 if pos < i {
734 b.WriteString(s[pos:i])
735 }
736 b.WriteByte(c)
737 pos = i + 1
738 }
739 }
740 if pos < len(s) {
741 b.WriteString(s[pos:])
742 }
743 return b.String()
744 }
745 return Map(unicode.ToLower, s)
746 }
747
748
749
750 func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
751
752
753
754 func ToUpperSpecial(c unicode.SpecialCase, s string) string {
755 return Map(c.ToUpper, s)
756 }
757
758
759
760 func ToLowerSpecial(c unicode.SpecialCase, s string) string {
761 return Map(c.ToLower, s)
762 }
763
764
765
766 func ToTitleSpecial(c unicode.SpecialCase, s string) string {
767 return Map(c.ToTitle, s)
768 }
769
770
771
772 func ToValidUTF8(s, replacement string) string {
773 var b Builder
774
775 for i, c := range s {
776 if c != utf8.RuneError {
777 continue
778 }
779
780 _, wid := utf8.DecodeRuneInString(s[i:])
781 if wid == 1 {
782 b.Grow(len(s) + len(replacement))
783 b.WriteString(s[:i])
784 s = s[i:]
785 break
786 }
787 }
788
789
790 if b.Cap() == 0 {
791 return s
792 }
793
794 invalid := false
795 for i := 0; i < len(s); {
796 c := s[i]
797 if c < utf8.RuneSelf {
798 i++
799 invalid = false
800 b.WriteByte(c)
801 continue
802 }
803 _, wid := utf8.DecodeRuneInString(s[i:])
804 if wid == 1 {
805 i++
806 if !invalid {
807 invalid = true
808 b.WriteString(replacement)
809 }
810 continue
811 }
812 invalid = false
813 b.WriteString(s[i : i+wid])
814 i += wid
815 }
816
817 return b.String()
818 }
819
820
821
822 func isSeparator(r rune) bool {
823
824 if r <= 0x7F {
825 switch {
826 case '0' <= r && r <= '9':
827 return false
828 case 'a' <= r && r <= 'z':
829 return false
830 case 'A' <= r && r <= 'Z':
831 return false
832 case r == '_':
833 return false
834 }
835 return true
836 }
837
838 if unicode.IsLetter(r) || unicode.IsDigit(r) {
839 return false
840 }
841
842 return unicode.IsSpace(r)
843 }
844
845
846
847
848
849
850 func Title(s string) string {
851
852
853
854 prev := ' '
855 return Map(
856 func(r rune) rune {
857 if isSeparator(prev) {
858 prev = r
859 return unicode.ToTitle(r)
860 }
861 prev = r
862 return r
863 },
864 s)
865 }
866
867
868
869 func TrimLeftFunc(s string, f func(rune) bool) string {
870 i := indexFunc(s, f, false)
871 if i == -1 {
872 return ""
873 }
874 return s[i:]
875 }
876
877
878
879 func TrimRightFunc(s string, f func(rune) bool) string {
880 i := lastIndexFunc(s, f, false)
881 if i >= 0 {
882 _, wid := utf8.DecodeRuneInString(s[i:])
883 i += wid
884 } else {
885 i++
886 }
887 return s[0:i]
888 }
889
890
891
892 func TrimFunc(s string, f func(rune) bool) string {
893 return TrimRightFunc(TrimLeftFunc(s, f), f)
894 }
895
896
897
898 func IndexFunc(s string, f func(rune) bool) int {
899 return indexFunc(s, f, true)
900 }
901
902
903
904 func LastIndexFunc(s string, f func(rune) bool) int {
905 return lastIndexFunc(s, f, true)
906 }
907
908
909
910
911 func indexFunc(s string, f func(rune) bool, truth bool) int {
912 for i, r := range s {
913 if f(r) == truth {
914 return i
915 }
916 }
917 return -1
918 }
919
920
921
922
923 func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
924 for i := len(s); i > 0; {
925 r, size := utf8.DecodeLastRuneInString(s[0:i])
926 i -= size
927 if f(r) == truth {
928 return i
929 }
930 }
931 return -1
932 }
933
934
935
936
937
938
939
940
941
942 type asciiSet [8]uint32
943
944
945
946 func makeASCIISet(chars string) (as asciiSet, ok bool) {
947 for i := 0; i < len(chars); i++ {
948 c := chars[i]
949 if c >= utf8.RuneSelf {
950 return as, false
951 }
952 as[c/32] |= 1 << (c % 32)
953 }
954 return as, true
955 }
956
957
958 func (as *asciiSet) contains(c byte) bool {
959 return (as[c/32] & (1 << (c % 32))) != 0
960 }
961
962
963
964 func Trim(s, cutset string) string {
965 if s == "" || cutset == "" {
966 return s
967 }
968 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
969 return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
970 }
971 if as, ok := makeASCIISet(cutset); ok {
972 return trimLeftASCII(trimRightASCII(s, &as), &as)
973 }
974 return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)
975 }
976
977
978
979
980
981 func TrimLeft(s, cutset string) string {
982 if s == "" || cutset == "" {
983 return s
984 }
985 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
986 return trimLeftByte(s, cutset[0])
987 }
988 if as, ok := makeASCIISet(cutset); ok {
989 return trimLeftASCII(s, &as)
990 }
991 return trimLeftUnicode(s, cutset)
992 }
993
994 func trimLeftByte(s string, c byte) string {
995 for len(s) > 0 && s[0] == c {
996 s = s[1:]
997 }
998 return s
999 }
1000
1001 func trimLeftASCII(s string, as *asciiSet) string {
1002 for len(s) > 0 {
1003 if !as.contains(s[0]) {
1004 break
1005 }
1006 s = s[1:]
1007 }
1008 return s
1009 }
1010
1011 func trimLeftUnicode(s, cutset string) string {
1012 for len(s) > 0 {
1013 r, n := utf8.DecodeRuneInString(s)
1014 if !ContainsRune(cutset, r) {
1015 break
1016 }
1017 s = s[n:]
1018 }
1019 return s
1020 }
1021
1022
1023
1024
1025
1026 func TrimRight(s, cutset string) string {
1027 if s == "" || cutset == "" {
1028 return s
1029 }
1030 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
1031 return trimRightByte(s, cutset[0])
1032 }
1033 if as, ok := makeASCIISet(cutset); ok {
1034 return trimRightASCII(s, &as)
1035 }
1036 return trimRightUnicode(s, cutset)
1037 }
1038
1039 func trimRightByte(s string, c byte) string {
1040 for len(s) > 0 && s[len(s)-1] == c {
1041 s = s[:len(s)-1]
1042 }
1043 return s
1044 }
1045
1046 func trimRightASCII(s string, as *asciiSet) string {
1047 for len(s) > 0 {
1048 if !as.contains(s[len(s)-1]) {
1049 break
1050 }
1051 s = s[:len(s)-1]
1052 }
1053 return s
1054 }
1055
1056 func trimRightUnicode(s, cutset string) string {
1057 for len(s) > 0 {
1058 r, n := rune(s[len(s)-1]), 1
1059 if r >= utf8.RuneSelf {
1060 r, n = utf8.DecodeLastRuneInString(s)
1061 }
1062 if !ContainsRune(cutset, r) {
1063 break
1064 }
1065 s = s[:len(s)-n]
1066 }
1067 return s
1068 }
1069
1070
1071
1072
1073 func TrimSpace(s string) string {
1074
1075 for lo, c := range []byte(s) {
1076 if c >= utf8.RuneSelf {
1077
1078
1079 return TrimFunc(s[lo:], unicode.IsSpace)
1080 }
1081 if asciiSpace[c] != 0 {
1082 continue
1083 }
1084 s = s[lo:]
1085
1086 for hi := len(s) - 1; hi >= 0; hi-- {
1087 c := s[hi]
1088 if c >= utf8.RuneSelf {
1089 return TrimRightFunc(s[:hi+1], unicode.IsSpace)
1090 }
1091 if asciiSpace[c] == 0 {
1092
1093
1094
1095 return s[:hi+1]
1096 }
1097 }
1098 }
1099 return ""
1100 }
1101
1102
1103
1104 func TrimPrefix(s, prefix string) string {
1105 return stringslite.TrimPrefix(s, prefix)
1106 }
1107
1108
1109
1110 func TrimSuffix(s, suffix string) string {
1111 return stringslite.TrimSuffix(s, suffix)
1112 }
1113
1114
1115
1116
1117
1118
1119
1120 func Replace(s, old, new string, n int) string {
1121 if old == new || n == 0 {
1122 return s
1123 }
1124
1125
1126 if m := Count(s, old); m == 0 {
1127 return s
1128 } else if n < 0 || m < n {
1129 n = m
1130 }
1131
1132
1133 var b Builder
1134 b.Grow(len(s) + n*(len(new)-len(old)))
1135 start := 0
1136 if len(old) > 0 {
1137 for range n {
1138 j := start + Index(s[start:], old)
1139 b.WriteString(s[start:j])
1140 b.WriteString(new)
1141 start = j + len(old)
1142 }
1143 } else {
1144 b.WriteString(new)
1145 for range n - 1 {
1146 _, wid := utf8.DecodeRuneInString(s[start:])
1147 j := start + wid
1148 b.WriteString(s[start:j])
1149 b.WriteString(new)
1150 start = j
1151 }
1152 }
1153 b.WriteString(s[start:])
1154 return b.String()
1155 }
1156
1157
1158
1159
1160
1161
1162 func ReplaceAll(s, old, new string) string {
1163 return Replace(s, old, new, -1)
1164 }
1165
1166
1167
1168
1169 func EqualFold(s, t string) bool {
1170
1171 i := 0
1172 for n := min(len(s), len(t)); i < n; i++ {
1173 sr := s[i]
1174 tr := t[i]
1175 if sr|tr >= utf8.RuneSelf {
1176 goto hasUnicode
1177 }
1178
1179
1180 if tr == sr {
1181 continue
1182 }
1183
1184
1185 if tr < sr {
1186 tr, sr = sr, tr
1187 }
1188
1189 if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' {
1190 continue
1191 }
1192 return false
1193 }
1194
1195 return len(s) == len(t)
1196
1197 hasUnicode:
1198 s = s[i:]
1199 t = t[i:]
1200 for _, sr := range s {
1201
1202 if len(t) == 0 {
1203 return false
1204 }
1205
1206
1207 tr, size := utf8.DecodeRuneInString(t)
1208 t = t[size:]
1209
1210
1211
1212
1213 if tr == sr {
1214 continue
1215 }
1216
1217
1218 if tr < sr {
1219 tr, sr = sr, tr
1220 }
1221
1222 if tr < utf8.RuneSelf {
1223
1224 if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' {
1225 continue
1226 }
1227 return false
1228 }
1229
1230
1231
1232 r := unicode.SimpleFold(sr)
1233 for r != sr && r < tr {
1234 r = unicode.SimpleFold(r)
1235 }
1236 if r == tr {
1237 continue
1238 }
1239 return false
1240 }
1241
1242
1243 return len(t) == 0
1244 }
1245
1246
1247 func Index(s, substr string) int {
1248 return stringslite.Index(s, substr)
1249 }
1250
1251
1252
1253
1254
1255 func Cut(s, sep string) (before, after string, found bool) {
1256 return stringslite.Cut(s, sep)
1257 }
1258
1259
1260
1261
1262
1263 func CutPrefix(s, prefix string) (after string, found bool) {
1264 return stringslite.CutPrefix(s, prefix)
1265 }
1266
1267
1268
1269
1270
1271 func CutSuffix(s, suffix string) (before string, found bool) {
1272 return stringslite.CutSuffix(s, suffix)
1273 }
1274
View as plain text