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 "unsafe"
17 )
18
19 const maxInt = int(^uint(0) >> 1)
20
21
22
23
24 func explode(s string, n int) []string {
25 l := utf8.RuneCountInString(s)
26 if n < 0 || n > l {
27 n = l
28 }
29 a := make([]string, n)
30 for i := 0; i < n-1; i++ {
31 _, size := utf8.DecodeRuneInString(s)
32 a[i] = s[:size]
33 s = s[size:]
34 }
35 if n > 0 {
36 a[n-1] = s
37 }
38 return a
39 }
40
41
42
43 func Count(s, substr string) int {
44
45 if len(substr) == 0 {
46 return utf8.RuneCountInString(s) + 1
47 }
48 if len(substr) == 1 {
49 return bytealg.CountString(s, substr[0])
50 }
51 n := 0
52 for {
53 i := Index(s, substr)
54 if i == -1 {
55 return n
56 }
57 n++
58 s = s[i+len(substr):]
59 }
60 }
61
62
63 func Contains(s, substr string) bool {
64 return Index(s, substr) >= 0
65 }
66
67
68 func ContainsAny(s, chars string) bool {
69 return IndexAny(s, chars) >= 0
70 }
71
72
73 func ContainsRune(s string, r rune) bool {
74 return IndexRune(s, r) >= 0
75 }
76
77
78
79 func ContainsFunc(s string, f func(rune) bool) bool {
80 return IndexFunc(s, f) >= 0
81 }
82
83
84 func LastIndex(s, substr string) int {
85 n := len(substr)
86 switch {
87 case n == 0:
88 return len(s)
89 case n == 1:
90 return bytealg.LastIndexByteString(s, substr[0])
91 case n == len(s):
92 if substr == s {
93 return 0
94 }
95 return -1
96 case n > len(s):
97 return -1
98 }
99 return bytealg.LastIndexRabinKarp(s, substr)
100 }
101
102
103 func IndexByte(s string, c byte) int {
104 return stringslite.IndexByte(s, c)
105 }
106
107
108
109
110
111 func IndexRune(s string, r rune) int {
112 const haveFastIndex = bytealg.MaxBruteForce > 0
113 switch {
114 case 0 <= r && r < utf8.RuneSelf:
115 return IndexByte(s, byte(r))
116 case r == utf8.RuneError:
117 for i, r := range s {
118 if r == utf8.RuneError {
119 return i
120 }
121 }
122 return -1
123 case !utf8.ValidRune(r):
124 return -1
125 default:
126
127
128
129 rs := string(r)
130 last := len(rs) - 1
131 i := last
132 fails := 0
133 for i < len(s) {
134 if s[i] != rs[last] {
135 o := IndexByte(s[i+1:], rs[last])
136 if o < 0 {
137 return -1
138 }
139 i += o + 1
140 }
141
142 for j := 1; j < len(rs); j++ {
143 if s[i-j] != rs[last-j] {
144 goto next
145 }
146 }
147 return i - last
148 next:
149 fails++
150 i++
151 if (haveFastIndex && fails > bytealg.Cutover(i)) && i < len(s) ||
152 (!haveFastIndex && fails >= 4+i>>4 && i < len(s)) {
153 goto fallback
154 }
155 }
156 return -1
157
158 fallback:
159
160 if haveFastIndex {
161 if j := bytealg.IndexString(s[i-last:], rs); j >= 0 {
162 return i + j - last
163 }
164 } else {
165 c0 := rs[last]
166 c1 := rs[last-1]
167 loop:
168 for ; i < len(s); i++ {
169 if s[i] == c0 && s[i-1] == c1 {
170 for k := 2; k < len(rs); k++ {
171 if s[i-k] != rs[last-k] {
172 continue loop
173 }
174 }
175 return i - last
176 }
177 }
178 }
179 return -1
180 }
181 }
182
183
184
185 func IndexAny(s, chars string) int {
186 if chars == "" {
187
188 return -1
189 }
190 if len(chars) == 1 {
191
192 r := rune(chars[0])
193 if r >= utf8.RuneSelf {
194 r = utf8.RuneError
195 }
196 return IndexRune(s, r)
197 }
198 if shouldUseASCIISet(len(s)) {
199 if as, isASCII := makeASCIISet(chars); isASCII {
200 for i := 0; i < len(s); i++ {
201 if as.contains(s[i]) {
202 return i
203 }
204 }
205 return -1
206 }
207 }
208 for i, c := range s {
209 if IndexRune(chars, c) >= 0 {
210 return i
211 }
212 }
213 return -1
214 }
215
216
217
218
219 func LastIndexAny(s, chars string) int {
220 if chars == "" {
221
222 return -1
223 }
224 if len(s) == 1 {
225 rc := rune(s[0])
226 if rc >= utf8.RuneSelf {
227 rc = utf8.RuneError
228 }
229 if IndexRune(chars, rc) >= 0 {
230 return 0
231 }
232 return -1
233 }
234 if shouldUseASCIISet(len(s)) {
235 if as, isASCII := makeASCIISet(chars); isASCII {
236 for i := len(s) - 1; i >= 0; i-- {
237 if as.contains(s[i]) {
238 return i
239 }
240 }
241 return -1
242 }
243 }
244 if len(chars) == 1 {
245 rc := rune(chars[0])
246 if rc >= utf8.RuneSelf {
247 rc = utf8.RuneError
248 }
249 for i := len(s); i > 0; {
250 r, size := utf8.DecodeLastRuneInString(s[:i])
251 i -= size
252 if rc == r {
253 return i
254 }
255 }
256 return -1
257 }
258 for i := len(s); i > 0; {
259 r, size := utf8.DecodeLastRuneInString(s[:i])
260 i -= size
261 if IndexRune(chars, r) >= 0 {
262 return i
263 }
264 }
265 return -1
266 }
267
268
269 func LastIndexByte(s string, c byte) int {
270 return bytealg.LastIndexByteString(s, c)
271 }
272
273
274
275 func genSplit(s, sep string, sepSave, n int) []string {
276 if n == 0 {
277 return nil
278 }
279 if sep == "" {
280 return explode(s, n)
281 }
282 if n < 0 {
283 n = Count(s, sep) + 1
284 }
285
286 n = min(n, len(s)+1)
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, r := range s {
438 if f(r) {
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 b := bytealg.MakeNoZero(len(s))[:len(s):len(s)]
685 for i := 0; i < len(s); i++ {
686 c := s[i]
687 if 'a' <= c && c <= 'z' {
688 c -= 'a' - 'A'
689 }
690 b[i] = c
691 }
692 return unsafe.String(unsafe.SliceData(b), len(b))
693 }
694 return Map(unicode.ToUpper, s)
695 }
696
697
698 func ToLower(s string) string {
699 isASCII, hasUpper := true, false
700 for i := 0; i < len(s); i++ {
701 c := s[i]
702 if c >= utf8.RuneSelf {
703 isASCII = false
704 break
705 }
706 hasUpper = hasUpper || ('A' <= c && c <= 'Z')
707 }
708
709 if isASCII {
710 if !hasUpper {
711 return s
712 }
713 b := bytealg.MakeNoZero(len(s))[:len(s):len(s)]
714 for i := 0; i < len(s); i++ {
715 c := s[i]
716 if 'A' <= c && c <= 'Z' {
717 c += 'a' - 'A'
718 }
719 b[i] = c
720 }
721 return unsafe.String(unsafe.SliceData(b), len(b))
722 }
723 return Map(unicode.ToLower, s)
724 }
725
726
727
728 func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
729
730
731
732 func ToUpperSpecial(c unicode.SpecialCase, s string) string {
733 return Map(c.ToUpper, s)
734 }
735
736
737
738 func ToLowerSpecial(c unicode.SpecialCase, s string) string {
739 return Map(c.ToLower, s)
740 }
741
742
743
744 func ToTitleSpecial(c unicode.SpecialCase, s string) string {
745 return Map(c.ToTitle, s)
746 }
747
748
749
750 func ToValidUTF8(s, replacement string) string {
751 var b Builder
752
753 for i, c := range s {
754 if c != utf8.RuneError {
755 continue
756 }
757
758 _, wid := utf8.DecodeRuneInString(s[i:])
759 if wid == 1 {
760 b.Grow(len(s) + len(replacement))
761 b.WriteString(s[:i])
762 s = s[i:]
763 break
764 }
765 }
766
767
768 if b.Cap() == 0 {
769 return s
770 }
771
772 invalid := false
773 for i := 0; i < len(s); {
774 c := s[i]
775 if c < utf8.RuneSelf {
776 i++
777 invalid = false
778 b.WriteByte(c)
779 continue
780 }
781 _, wid := utf8.DecodeRuneInString(s[i:])
782 if wid == 1 {
783 i++
784 if !invalid {
785 invalid = true
786 b.WriteString(replacement)
787 }
788 continue
789 }
790 invalid = false
791 b.WriteString(s[i : i+wid])
792 i += wid
793 }
794
795 return b.String()
796 }
797
798
799
800 func isSeparator(r rune) bool {
801
802 if r <= 0x7F {
803 switch {
804 case '0' <= r && r <= '9':
805 return false
806 case 'a' <= r && r <= 'z':
807 return false
808 case 'A' <= r && r <= 'Z':
809 return false
810 case r == '_':
811 return false
812 }
813 return true
814 }
815
816 if unicode.IsLetter(r) || unicode.IsDigit(r) {
817 return false
818 }
819
820 return unicode.IsSpace(r)
821 }
822
823
824
825
826
827
828 func Title(s string) string {
829
830
831
832 prev := ' '
833 return Map(
834 func(r rune) rune {
835 if isSeparator(prev) {
836 prev = r
837 return unicode.ToTitle(r)
838 }
839 prev = r
840 return r
841 },
842 s)
843 }
844
845
846
847 func TrimLeftFunc(s string, f func(rune) bool) string {
848 i := indexFunc(s, f, false)
849 if i == -1 {
850 return ""
851 }
852 return s[i:]
853 }
854
855
856
857 func TrimRightFunc(s string, f func(rune) bool) string {
858 i := lastIndexFunc(s, f, false)
859 if i >= 0 {
860 _, wid := utf8.DecodeRuneInString(s[i:])
861 i += wid
862 } else {
863 i++
864 }
865 return s[0:i]
866 }
867
868
869
870 func TrimFunc(s string, f func(rune) bool) string {
871 return TrimRightFunc(TrimLeftFunc(s, f), f)
872 }
873
874
875
876 func IndexFunc(s string, f func(rune) bool) int {
877 return indexFunc(s, f, true)
878 }
879
880
881
882 func LastIndexFunc(s string, f func(rune) bool) int {
883 return lastIndexFunc(s, f, true)
884 }
885
886
887
888
889 func indexFunc(s string, f func(rune) bool, truth bool) int {
890 for i, r := range s {
891 if f(r) == truth {
892 return i
893 }
894 }
895 return -1
896 }
897
898
899
900
901 func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
902 for i := len(s); i > 0; {
903 r, size := utf8.DecodeLastRuneInString(s[0:i])
904 i -= size
905 if f(r) == truth {
906 return i
907 }
908 }
909 return -1
910 }
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927 type asciiSet [256]bool
928
929
930
931 func makeASCIISet(chars string) (as asciiSet, ok bool) {
932 for i := 0; i < len(chars); i++ {
933 c := chars[i]
934 if c >= utf8.RuneSelf {
935 return as, false
936 }
937 as[c] = true
938 }
939 return as, true
940 }
941
942
943 func (as *asciiSet) contains(c byte) bool {
944 return as[c]
945 }
946
947
948
949
950
951
952
953 func shouldUseASCIISet(bufLen int) bool {
954 return bufLen > 8
955 }
956
957
958
959 func Trim(s, cutset string) string {
960 if s == "" || cutset == "" {
961 return s
962 }
963 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
964 return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
965 }
966 if as, ok := makeASCIISet(cutset); ok {
967 return trimLeftASCII(trimRightASCII(s, &as), &as)
968 }
969 return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)
970 }
971
972
973
974
975
976 func TrimLeft(s, cutset string) string {
977 if s == "" || cutset == "" {
978 return s
979 }
980 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
981 return trimLeftByte(s, cutset[0])
982 }
983 if as, ok := makeASCIISet(cutset); ok {
984 return trimLeftASCII(s, &as)
985 }
986 return trimLeftUnicode(s, cutset)
987 }
988
989 func trimLeftByte(s string, c byte) string {
990 for len(s) > 0 && s[0] == c {
991 s = s[1:]
992 }
993 return s
994 }
995
996 func trimLeftASCII(s string, as *asciiSet) string {
997 for len(s) > 0 {
998 if !as.contains(s[0]) {
999 break
1000 }
1001 s = s[1:]
1002 }
1003 return s
1004 }
1005
1006 func trimLeftUnicode(s, cutset string) string {
1007 for len(s) > 0 {
1008 r, n := utf8.DecodeRuneInString(s)
1009 if !ContainsRune(cutset, r) {
1010 break
1011 }
1012 s = s[n:]
1013 }
1014 return s
1015 }
1016
1017
1018
1019
1020
1021 func TrimRight(s, cutset string) string {
1022 if s == "" || cutset == "" {
1023 return s
1024 }
1025 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
1026 return trimRightByte(s, cutset[0])
1027 }
1028 if as, ok := makeASCIISet(cutset); ok {
1029 return trimRightASCII(s, &as)
1030 }
1031 return trimRightUnicode(s, cutset)
1032 }
1033
1034 func trimRightByte(s string, c byte) string {
1035 for len(s) > 0 && s[len(s)-1] == c {
1036 s = s[:len(s)-1]
1037 }
1038 return s
1039 }
1040
1041 func trimRightASCII(s string, as *asciiSet) string {
1042 for len(s) > 0 {
1043 if !as.contains(s[len(s)-1]) {
1044 break
1045 }
1046 s = s[:len(s)-1]
1047 }
1048 return s
1049 }
1050
1051 func trimRightUnicode(s, cutset string) string {
1052 for len(s) > 0 {
1053 r, n := rune(s[len(s)-1]), 1
1054 if r >= utf8.RuneSelf {
1055 r, n = utf8.DecodeLastRuneInString(s)
1056 }
1057 if !ContainsRune(cutset, r) {
1058 break
1059 }
1060 s = s[:len(s)-n]
1061 }
1062 return s
1063 }
1064
1065 func trimSpaceUnicode(s string) string {
1066 for len(s) > 0 {
1067 r, n := utf8.DecodeRuneInString(s)
1068 if !stringslite.IsSpace(r) {
1069 break
1070 }
1071 s = s[n:]
1072 }
1073 return trimRightSpaceUnicode(s)
1074 }
1075
1076 func trimRightSpaceUnicode(s string) string {
1077 for len(s) > 0 {
1078 r, n := rune(s[len(s)-1]), 1
1079 if r >= utf8.RuneSelf {
1080 r, n = utf8.DecodeLastRuneInString(s)
1081 }
1082 if !stringslite.IsSpace(r) {
1083 break
1084 }
1085 s = s[:len(s)-n]
1086 }
1087 return s
1088 }
1089
1090
1091
1092
1093 func TrimSpace(s string) string {
1094
1095 for lo, c := range []byte(s) {
1096 if c >= utf8.RuneSelf {
1097
1098
1099 return trimSpaceUnicode(s[lo:])
1100 }
1101 if asciiSpace[c] != 0 {
1102 continue
1103 }
1104 s = s[lo:]
1105
1106 for hi := len(s) - 1; hi >= 0; hi-- {
1107 c := s[hi]
1108 if c >= utf8.RuneSelf {
1109 return trimRightSpaceUnicode(s[:hi+1])
1110 }
1111 if asciiSpace[c] == 0 {
1112
1113
1114
1115 return s[:hi+1]
1116 }
1117 }
1118 }
1119 return ""
1120 }
1121
1122
1123
1124 func TrimPrefix(s, prefix string) string {
1125 return stringslite.TrimPrefix(s, prefix)
1126 }
1127
1128
1129
1130 func TrimSuffix(s, suffix string) string {
1131 return stringslite.TrimSuffix(s, suffix)
1132 }
1133
1134
1135
1136
1137
1138
1139
1140 func Replace(s, old, new string, n int) string {
1141 if old == new || n == 0 {
1142 return s
1143 }
1144
1145
1146 if m := Count(s, old); m == 0 {
1147 return s
1148 } else if n < 0 || m < n {
1149 n = m
1150 }
1151
1152
1153 var b Builder
1154 b.Grow(len(s) + n*(len(new)-len(old)))
1155 start := 0
1156 if len(old) > 0 {
1157 for range n {
1158 j := start + Index(s[start:], old)
1159 b.WriteString(s[start:j])
1160 b.WriteString(new)
1161 start = j + len(old)
1162 }
1163 } else {
1164 b.WriteString(new)
1165 for range n - 1 {
1166 _, wid := utf8.DecodeRuneInString(s[start:])
1167 j := start + wid
1168 b.WriteString(s[start:j])
1169 b.WriteString(new)
1170 start = j
1171 }
1172 }
1173 b.WriteString(s[start:])
1174 return b.String()
1175 }
1176
1177
1178
1179
1180
1181
1182 func ReplaceAll(s, old, new string) string {
1183 return Replace(s, old, new, -1)
1184 }
1185
1186
1187
1188
1189 func EqualFold(s, t string) bool {
1190
1191 i := 0
1192 for n := min(len(s), len(t)); i < n; i++ {
1193 sr := s[i]
1194 tr := t[i]
1195 if sr|tr >= utf8.RuneSelf {
1196 goto hasUnicode
1197 }
1198
1199
1200 if tr == sr {
1201 continue
1202 }
1203
1204
1205 if tr < sr {
1206 tr, sr = sr, tr
1207 }
1208
1209 if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' {
1210 continue
1211 }
1212 return false
1213 }
1214
1215 return len(s) == len(t)
1216
1217 hasUnicode:
1218 s = s[i:]
1219 t = t[i:]
1220 for _, sr := range s {
1221
1222 if len(t) == 0 {
1223 return false
1224 }
1225
1226
1227 tr, size := utf8.DecodeRuneInString(t)
1228 t = t[size:]
1229
1230
1231
1232
1233 if tr == sr {
1234 continue
1235 }
1236
1237
1238 if tr < sr {
1239 tr, sr = sr, tr
1240 }
1241
1242 if tr < utf8.RuneSelf {
1243
1244 if 'A' <= sr && sr <= 'Z' && tr == sr+'a'-'A' {
1245 continue
1246 }
1247 return false
1248 }
1249
1250
1251
1252 r := unicode.SimpleFold(sr)
1253 for r != sr && r < tr {
1254 r = unicode.SimpleFold(r)
1255 }
1256 if r == tr {
1257 continue
1258 }
1259 return false
1260 }
1261
1262
1263 return len(t) == 0
1264 }
1265
1266
1267 func Index(s, substr string) int {
1268 return stringslite.Index(s, substr)
1269 }
1270
1271
1272
1273
1274
1275 func Cut(s, sep string) (before, after string, found bool) {
1276 return stringslite.Cut(s, sep)
1277 }
1278
1279
1280
1281
1282
1283 func CutPrefix(s, prefix string) (after string, found bool) {
1284 return stringslite.CutPrefix(s, prefix)
1285 }
1286
1287
1288
1289
1290
1291 func CutSuffix(s, suffix string) (before string, found bool) {
1292 return stringslite.CutSuffix(s, suffix)
1293 }
1294
1295
1296
1297
1298
1299 func CutLast(s, sep string) (before, after string, found bool) {
1300 if i := LastIndex(s, sep); i >= 0 {
1301 return s[:i], s[i+len(sep):], true
1302 }
1303 return s, "", false
1304 }
1305
View as plain text