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