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