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