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