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