codekingpro/portable-devtools
114k
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5// Package strings implements simple functions to manipulate UTF-8 encoded strings.6//7// For information about UTF-8 strings in Go, see https://blog.golang.org/strings.8package strings9 10import (11 "internal/bytealg"12 "internal/stringslite"13 "math/bits"14 "unicode"15 "unicode/utf8"16)17 18const maxInt = int(^uint(0) >> 1)19 20// explode splits s into a slice of UTF-8 strings,21// one string per Unicode character up to a maximum of n (n < 0 means no limit).22// Invalid UTF-8 bytes are sliced individually.23func explode(s string, n int) []string {24 l := utf8.RuneCountInString(s)25 if n < 0 || n > l {26 n = l27 }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] = s36 }37 return a38}39 40// Count counts the number of non-overlapping instances of substr in s.41// If substr is an empty string, Count returns 1 + the number of Unicode code points in s.42func Count(s, substr string) int {43 // special case44 if len(substr) == 0 {45 return utf8.RuneCountInString(s) + 146 }47 if len(substr) == 1 {48 return bytealg.CountString(s, substr[0])49 }50 n := 051 for {52 i := Index(s, substr)53 if i == -1 {54 return n55 }56 n++57 s = s[i+len(substr):]58 }59}60 61// Contains reports whether substr is within s.62func Contains(s, substr string) bool {63 return Index(s, substr) >= 064}65 66// ContainsAny reports whether any Unicode code points in chars are within s.67func ContainsAny(s, chars string) bool {68 return IndexAny(s, chars) >= 069}70 71// ContainsRune reports whether the Unicode code point r is within s.72func ContainsRune(s string, r rune) bool {73 return IndexRune(s, r) >= 074}75 76// ContainsFunc reports whether any Unicode code points r within s satisfy f(r).77func ContainsFunc(s string, f func(rune) bool) bool {78 return IndexFunc(s, f) >= 079}80 81// LastIndex returns the index of the last instance of substr in s, or -1 if substr is not present in s.82func 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 092 }93 return -194 case n > len(s):95 return -196 }97 // Rabin-Karp search from the end of the string98 hashss, pow := bytealg.HashStrRev(substr)99 last := len(s) - n100 var h uint32101 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 last106 }107 for i := last - 1; i >= 0; i-- {108 h *= bytealg.PrimeRK109 h += uint32(s[i])110 h -= pow * uint32(s[i+n])111 if h == hashss && s[i:i+n] == substr {112 return i113 }114 }115 return -1116}117 118// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.119func IndexByte(s string, c byte) int {120 return stringslite.IndexByte(s, c)121}122 123// IndexRune returns the index of the first instance of the Unicode code point124// r, or -1 if rune is not present in s.125// If r is [utf8.RuneError], it returns the first instance of any126// invalid UTF-8 byte sequence.127func IndexRune(s string, r rune) int {128 const haveFastIndex = bytealg.MaxBruteForce > 0129 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 i136 }137 }138 return -1139 case !utf8.ValidRune(r):140 return -1141 default:142 // Search for rune r using the last byte of its UTF-8 encoded form.143 // The distribution of the last byte is more uniform compared to the144 // first byte which has a 78% chance of being [240, 243, 244].145 rs := string(r)146 last := len(rs) - 1147 i := last148 fails := 0149 for i < len(s) {150 if s[i] != rs[last] {151 o := IndexByte(s[i+1:], rs[last])152 if o < 0 {153 return -1154 }155 i += o + 1156 }157 // Step backwards comparing bytes.158 for j := 1; j < len(rs); j++ {159 if s[i-j] != rs[last-j] {160 goto next161 }162 }163 return i - last164 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 fallback170 }171 }172 return -1173 174 fallback:175 // see comment in ../bytes/bytes.go176 if haveFastIndex {177 if j := bytealg.IndexString(s[i-last:], string(r)); j >= 0 {178 return i + j - last179 }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 loop189 }190 }191 return i - last192 }193 }194 }195 return -1196 }197}198 199// IndexAny returns the index of the first instance of any Unicode code point200// from chars in s, or -1 if no Unicode code point from chars is present in s.201func IndexAny(s, chars string) int {202 if chars == "" {203 // Avoid scanning all of s.204 return -1205 }206 if len(chars) == 1 {207 // Avoid scanning all of s.208 r := rune(chars[0])209 if r >= utf8.RuneSelf {210 r = utf8.RuneError211 }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 i219 }220 }221 return -1222 }223 }224 for i, c := range s {225 if IndexRune(chars, c) >= 0 {226 return i227 }228 }229 return -1230}231 232// LastIndexAny returns the index of the last instance of any Unicode code233// point from chars in s, or -1 if no Unicode code point from chars is234// present in s.235func LastIndexAny(s, chars string) int {236 if chars == "" {237 // Avoid scanning all of s.238 return -1239 }240 if len(s) == 1 {241 rc := rune(s[0])242 if rc >= utf8.RuneSelf {243 rc = utf8.RuneError244 }245 if IndexRune(chars, rc) >= 0 {246 return 0247 }248 return -1249 }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 i255 }256 }257 return -1258 }259 }260 if len(chars) == 1 {261 rc := rune(chars[0])262 if rc >= utf8.RuneSelf {263 rc = utf8.RuneError264 }265 for i := len(s); i > 0; {266 r, size := utf8.DecodeLastRuneInString(s[:i])267 i -= size268 if rc == r {269 return i270 }271 }272 return -1273 }274 for i := len(s); i > 0; {275 r, size := utf8.DecodeLastRuneInString(s[:i])276 i -= size277 if IndexRune(chars, r) >= 0 {278 return i279 }280 }281 return -1282}283 284// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.285func LastIndexByte(s string, c byte) int {286 return bytealg.LastIndexByteString(s, c)287}288 289// Generic split: splits after each instance of sep,290// including sepSave bytes of sep in the subarrays.291func genSplit(s, sep string, sepSave, n int) []string {292 if n == 0 {293 return nil294 }295 if sep == "" {296 return explode(s, n)297 }298 if n < 0 {299 n = Count(s, sep) + 1300 }301 302 if n > len(s)+1 {303 n = len(s) + 1304 }305 a := make([]string, n)306 n--307 i := 0308 for i < n {309 m := Index(s, sep)310 if m < 0 {311 break312 }313 a[i] = s[:m+sepSave]314 s = s[m+len(sep):]315 i++316 }317 a[i] = s318 return a[:i+1]319}320 321// SplitN slices s into substrings separated by sep and returns a slice of322// the substrings between those separators.323//324// The count determines the number of substrings to return:325// - n > 0: at most n substrings; the last substring will be the unsplit remainder;326// - n == 0: the result is nil (zero substrings);327// - n < 0: all substrings.328//329// Edge cases for s and sep (for example, empty strings) are handled330// as described in the documentation for [Split].331//332// To split around the first instance of a separator, see [Cut].333func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }334 335// SplitAfterN slices s into substrings after each instance of sep and336// returns a slice of those substrings.337//338// The count determines the number of substrings to return:339// - n > 0: at most n substrings; the last substring will be the unsplit remainder;340// - n == 0: the result is nil (zero substrings);341// - n < 0: all substrings.342//343// Edge cases for s and sep (for example, empty strings) are handled344// as described in the documentation for [SplitAfter].345func SplitAfterN(s, sep string, n int) []string {346 return genSplit(s, sep, len(sep), n)347}348 349// Split slices s into all substrings separated by sep and returns a slice of350// the substrings between those separators.351//352// If s does not contain sep and sep is not empty, Split returns a353// slice of length 1 whose only element is s.354//355// If sep is empty, Split splits after each UTF-8 sequence. If both s356// and sep are empty, Split returns an empty slice.357//358// It is equivalent to [SplitN] with a count of -1.359//360// To split around the first instance of a separator, see [Cut].361func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }362 363// SplitAfter slices s into all substrings after each instance of sep and364// returns a slice of those substrings.365//366// If s does not contain sep and sep is not empty, SplitAfter returns367// a slice of length 1 whose only element is s.368//369// If sep is empty, SplitAfter splits after each UTF-8 sequence. If370// both s and sep are empty, SplitAfter returns an empty slice.371//372// It is equivalent to [SplitAfterN] with a count of -1.373func SplitAfter(s, sep string) []string {374 return genSplit(s, sep, len(sep), -1)375}376 377var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}378 379// Fields splits the string s around each instance of one or more consecutive white space380// characters, as defined by [unicode.IsSpace], returning a slice of substrings of s or an381// empty slice if s contains only white space. Every element of the returned slice is382// non-empty. Unlike [Split], leading and trailing runs of white space characters383// are discarded.384func Fields(s string) []string {385 // First count the fields.386 // This is an exact count if s is ASCII, otherwise it is an approximation.387 n := 0388 wasSpace := 1389 // setBits is used to track which bits are set in the bytes of s.390 setBits := uint8(0)391 for i := 0; i < len(s); i++ {392 r := s[i]393 setBits |= r394 isSpace := int(asciiSpace[r])395 n += wasSpace & ^isSpace396 wasSpace = isSpace397 }398 399 if setBits >= utf8.RuneSelf {400 // Some runes in the input string are not ASCII.401 return FieldsFunc(s, unicode.IsSpace)402 }403 // ASCII fast path404 a := make([]string, n)405 na := 0406 fieldStart := 0407 i := 0408 // Skip spaces in the front of the input.409 for i < len(s) && asciiSpace[s[i]] != 0 {410 i++411 }412 fieldStart = i413 for i < len(s) {414 if asciiSpace[s[i]] == 0 {415 i++416 continue417 }418 a[na] = s[fieldStart:i]419 na++420 i++421 // Skip spaces in between fields.422 for i < len(s) && asciiSpace[s[i]] != 0 {423 i++424 }425 fieldStart = i426 }427 if fieldStart < len(s) { // Last field might end at EOF.428 a[na] = s[fieldStart:]429 }430 return a431}432 433// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)434// and returns an array of slices of s. If all code points in s satisfy f(c) or the435// string is empty, an empty slice is returned. Every element of the returned slice is436// non-empty. Unlike [Split], leading and trailing runs of code points satisfying f(c)437// are discarded.438//439// FieldsFunc makes no guarantees about the order in which it calls f(c)440// and assumes that f always returns the same value for a given c.441func FieldsFunc(s string, f func(rune) bool) []string {442 // A span is used to record a slice of s of the form s[start:end].443 // The start index is inclusive and the end index is exclusive.444 type span struct {445 start int446 end int447 }448 spans := make([]span, 0, 32)449 450 // Find the field start and end indices.451 // Doing this in a separate pass (rather than slicing the string s452 // and collecting the result substrings right away) is significantly453 // more efficient, possibly due to cache effects.454 start := -1 // valid span start if >= 0455 for end, rune := range s {456 if f(rune) {457 if start >= 0 {458 spans = append(spans, span{start, end})459 // Set start to a negative value.460 // Note: using -1 here consistently and reproducibly461 // slows down this code by a several percent on amd64.462 start = ^start463 }464 } else {465 if start < 0 {466 start = end467 }468 }469 }470 471 // Last field might end at EOF.472 if start >= 0 {473 spans = append(spans, span{start, len(s)})474 }475 476 // Create strings from recorded field indices.477 a := make([]string, len(spans))478 for i, span := range spans {479 a[i] = s[span.start:span.end]480 }481 482 return a483}484 485// Join concatenates the elements of its first argument to create a single string. The separator486// string sep is placed between elements in the resulting string.487func Join(elems []string, sep string) string {488 switch len(elems) {489 case 0:490 return ""491 case 1:492 return elems[0]493 }494 495 var n int496 if len(sep) > 0 {497 if len(sep) >= maxInt/(len(elems)-1) {498 panic("strings: Join output length overflow")499 }500 n += len(sep) * (len(elems) - 1)501 }502 for _, elem := range elems {503 if len(elem) > maxInt-n {504 panic("strings: Join output length overflow")505 }506 n += len(elem)507 }508 509 var b Builder510 b.Grow(n)511 b.WriteString(elems[0])512 for _, s := range elems[1:] {513 b.WriteString(sep)514 b.WriteString(s)515 }516 return b.String()517}518 519// HasPrefix reports whether the string s begins with prefix.520func HasPrefix(s, prefix string) bool {521 return stringslite.HasPrefix(s, prefix)522}523 524// HasSuffix reports whether the string s ends with suffix.525func HasSuffix(s, suffix string) bool {526 return stringslite.HasSuffix(s, suffix)527}528 529// Map returns a copy of the string s with all its characters modified530// according to the mapping function. If mapping returns a negative value, the character is531// dropped from the string with no replacement.532func Map(mapping func(rune) rune, s string) string {533 // In the worst case, the string can grow when mapped, making534 // things unpleasant. But it's so rare we barge in assuming it's535 // fine. It could also shrink but that falls out naturally.536 537 // The output buffer b is initialized on demand, the first538 // time a character differs.539 var b Builder540 541 for i, c := range s {542 r := mapping(c)543 if r == c && c != utf8.RuneError {544 continue545 }546 547 var width int548 if c == utf8.RuneError {549 c, width = utf8.DecodeRuneInString(s[i:])550 if width != 1 && r == c {551 continue552 }553 } else {554 width = utf8.RuneLen(c)555 }556 557 b.Grow(len(s) + utf8.UTFMax)558 b.WriteString(s[:i])559 if r >= 0 {560 b.WriteRune(r)561 }562 563 s = s[i+width:]564 break565 }566 567 // Fast path for unchanged input568 if b.Cap() == 0 { // didn't call b.Grow above569 return s570 }571 572 for _, c := range s {573 r := mapping(c)574 575 if r >= 0 {576 // common case577 // Due to inlining, it is more performant to determine if WriteByte should be578 // invoked rather than always call WriteRune579 if r < utf8.RuneSelf {580 b.WriteByte(byte(r))581 } else {582 // r is not an ASCII rune.583 b.WriteRune(r)584 }585 }586 }587 588 return b.String()589}590 591// According to static analysis, spaces, dashes, zeros, equals, and tabs592// are the most commonly repeated string literal,593// often used for display on fixed-width terminal windows.594// Pre-declare constants for these for O(1) repetition in the common-case.595const (596 repeatedSpaces = "" +597 " " +598 " "599 repeatedDashes = "" +600 "----------------------------------------------------------------" +601 "----------------------------------------------------------------"602 repeatedZeroes = "" +603 "0000000000000000000000000000000000000000000000000000000000000000"604 repeatedEquals = "" +605 "================================================================" +606 "================================================================"607 repeatedTabs = "" +608 "\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" +609 "\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"610)611 612// Repeat returns a new string consisting of count copies of the string s.613//614// It panics if count is negative or if the result of (len(s) * count)615// overflows.616func Repeat(s string, count int) string {617 switch count {618 case 0:619 return ""620 case 1:621 return s622 }623 624 // Since we cannot return an error on overflow,625 // we should panic if the repeat will generate an overflow.626 // See golang.org/issue/16237.627 if count < 0 {628 panic("strings: negative Repeat count")629 }630 hi, lo := bits.Mul(uint(len(s)), uint(count))631 if hi > 0 || lo > uint(maxInt) {632 panic("strings: Repeat output length overflow")633 }634 n := int(lo) // lo = len(s) * count635 636 if len(s) == 0 {637 return ""638 }639 640 // Optimize for commonly repeated strings of relatively short length.641 switch s[0] {642 case ' ', '-', '0', '=', '\t':643 switch {644 case n <= len(repeatedSpaces) && HasPrefix(repeatedSpaces, s):645 return repeatedSpaces[:n]646 case n <= len(repeatedDashes) && HasPrefix(repeatedDashes, s):647 return repeatedDashes[:n]648 case n <= len(repeatedZeroes) && HasPrefix(repeatedZeroes, s):649 return repeatedZeroes[:n]650 case n <= len(repeatedEquals) && HasPrefix(repeatedEquals, s):651 return repeatedEquals[:n]652 case n <= len(repeatedTabs) && HasPrefix(repeatedTabs, s):653 return repeatedTabs[:n]654 }655 }656 657 // Past a certain chunk size it is counterproductive to use658 // larger chunks as the source of the write, as when the source659 // is too large we are basically just thrashing the CPU D-cache.660 // So if the result length is larger than an empirically-found661 // limit (8KB), we stop growing the source string once the limit662 // is reached and keep reusing the same source string - that663 // should therefore be always resident in the L1 cache - until we664 // have completed the construction of the result.665 // This yields significant speedups (up to +100%) in cases where666 // the result length is large (roughly, over L2 cache size).667 const chunkLimit = 8 * 1024668 chunkMax := n669 if n > chunkLimit {670 chunkMax = chunkLimit / len(s) * len(s)671 if chunkMax == 0 {672 chunkMax = len(s)673 }674 }675 676 var b Builder677 b.Grow(n)678 b.WriteString(s)679 for b.Len() < n {680 chunk := min(n-b.Len(), b.Len(), chunkMax)681 b.WriteString(b.String()[:chunk])682 }683 return b.String()684}685 686// ToUpper returns s with all Unicode letters mapped to their upper case.687func ToUpper(s string) string {688 isASCII, hasLower := true, false689 for i := 0; i < len(s); i++ {690 c := s[i]691 if c >= utf8.RuneSelf {692 isASCII = false693 break694 }695 hasLower = hasLower || ('a' <= c && c <= 'z')696 }697 698 if isASCII { // optimize for ASCII-only strings.699 if !hasLower {700 return s701 }702 var (703 b Builder704 pos int705 )706 b.Grow(len(s))707 for i := 0; i < len(s); i++ {708 c := s[i]709 if 'a' <= c && c <= 'z' {710 c -= 'a' - 'A'711 if pos < i {712 b.WriteString(s[pos:i])713 }714 b.WriteByte(c)715 pos = i + 1716 }717 }718 if pos < len(s) {719 b.WriteString(s[pos:])720 }721 return b.String()722 }723 return Map(unicode.ToUpper, s)724}725 726// ToLower returns s with all Unicode letters mapped to their lower case.727func ToLower(s string) string {728 isASCII, hasUpper := true, false729 for i := 0; i < len(s); i++ {730 c := s[i]731 if c >= utf8.RuneSelf {732 isASCII = false733 break734 }735 hasUpper = hasUpper || ('A' <= c && c <= 'Z')736 }737 738 if isASCII { // optimize for ASCII-only strings.739 if !hasUpper {740 return s741 }742 var (743 b Builder744 pos int745 )746 b.Grow(len(s))747 for i := 0; i < len(s); i++ {748 c := s[i]749 if 'A' <= c && c <= 'Z' {750 c += 'a' - 'A'751 if pos < i {752 b.WriteString(s[pos:i])753 }754 b.WriteByte(c)755 pos = i + 1756 }757 }758 if pos < len(s) {759 b.WriteString(s[pos:])760 }761 return b.String()762 }763 return Map(unicode.ToLower, s)764}765 766// ToTitle returns a copy of the string s with all Unicode letters mapped to767// their Unicode title case.768func ToTitle(s string) string { return Map(unicode.ToTitle, s) }769 770// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their771// upper case using the case mapping specified by c.772func ToUpperSpecial(c unicode.SpecialCase, s string) string {773 return Map(c.ToUpper, s)774}775 776// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their777// lower case using the case mapping specified by c.778func ToLowerSpecial(c unicode.SpecialCase, s string) string {779 return Map(c.ToLower, s)780}781 782// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their783// Unicode title case, giving priority to the special casing rules.784func ToTitleSpecial(c unicode.SpecialCase, s string) string {785 return Map(c.ToTitle, s)786}787 788// ToValidUTF8 returns a copy of the string s with each run of invalid UTF-8 byte sequences789// replaced by the replacement string, which may be empty.790func ToValidUTF8(s, replacement string) string {791 var b Builder792 793 for i, c := range s {794 if c != utf8.RuneError {795 continue796 }797 798 _, wid := utf8.DecodeRuneInString(s[i:])799 if wid == 1 {800 b.Grow(len(s) + len(replacement))801 b.WriteString(s[:i])802 s = s[i:]803 break804 }805 }806 807 // Fast path for unchanged input808 if b.Cap() == 0 { // didn't call b.Grow above809 return s810 }811 812 invalid := false // previous byte was from an invalid UTF-8 sequence813 for i := 0; i < len(s); {814 c := s[i]815 if c < utf8.RuneSelf {816 i++817 invalid = false818 b.WriteByte(c)819 continue820 }821 _, wid := utf8.DecodeRuneInString(s[i:])822 if wid == 1 {823 i++824 if !invalid {825 invalid = true826 b.WriteString(replacement)827 }828 continue829 }830 invalid = false831 b.WriteString(s[i : i+wid])832 i += wid833 }834 835 return b.String()836}837 838// isSeparator reports whether the rune could mark a word boundary.839// TODO: update when package unicode captures more of the properties.840func isSeparator(r rune) bool {841 // ASCII alphanumerics and underscore are not separators842 if r <= 0x7F {843 switch {844 case '0' <= r && r <= '9':845 return false846 case 'a' <= r && r <= 'z':847 return false848 case 'A' <= r && r <= 'Z':849 return false850 case r == '_':851 return false852 }853 return true854 }855 // Letters and digits are not separators856 if unicode.IsLetter(r) || unicode.IsDigit(r) {857 return false858 }859 // Otherwise, all we can do for now is treat spaces as separators.860 return unicode.IsSpace(r)861}862 863// Title returns a copy of the string s with all Unicode letters that begin words864// mapped to their Unicode title case.865//866// Deprecated: The rule Title uses for word boundaries does not handle Unicode867// punctuation properly. Use golang.org/x/text/cases instead.868func Title(s string) string {869 // Use a closure here to remember state.870 // Hackish but effective. Depends on Map scanning in order and calling871 // the closure once per rune.872 prev := ' '873 return Map(874 func(r rune) rune {875 if isSeparator(prev) {876 prev = r877 return unicode.ToTitle(r)878 }879 prev = r880 return r881 },882 s)883}884 885// TrimLeftFunc returns a slice of the string s with all leading886// Unicode code points c satisfying f(c) removed.887func TrimLeftFunc(s string, f func(rune) bool) string {888 i := indexFunc(s, f, false)889 if i == -1 {890 return ""891 }892 return s[i:]893}894 895// TrimRightFunc returns a slice of the string s with all trailing896// Unicode code points c satisfying f(c) removed.897func TrimRightFunc(s string, f func(rune) bool) string {898 i := lastIndexFunc(s, f, false)899 if i >= 0 {900 _, wid := utf8.DecodeRuneInString(s[i:])901 i += wid902 } else {903 i++904 }905 return s[0:i]906}907 908// TrimFunc returns a slice of the string s with all leading909// and trailing Unicode code points c satisfying f(c) removed.910func TrimFunc(s string, f func(rune) bool) string {911 return TrimRightFunc(TrimLeftFunc(s, f), f)912}913 914// IndexFunc returns the index into s of the first Unicode915// code point satisfying f(c), or -1 if none do.916func IndexFunc(s string, f func(rune) bool) int {917 return indexFunc(s, f, true)918}919 920// LastIndexFunc returns the index into s of the last921// Unicode code point satisfying f(c), or -1 if none do.922func LastIndexFunc(s string, f func(rune) bool) int {923 return lastIndexFunc(s, f, true)924}925 926// indexFunc is the same as IndexFunc except that if927// truth==false, the sense of the predicate function is928// inverted.929func indexFunc(s string, f func(rune) bool, truth bool) int {930 for i, r := range s {931 if f(r) == truth {932 return i933 }934 }935 return -1936}937 938// lastIndexFunc is the same as LastIndexFunc except that if939// truth==false, the sense of the predicate function is940// inverted.941func lastIndexFunc(s string, f func(rune) bool, truth bool) int {942 for i := len(s); i > 0; {943 r, size := utf8.DecodeLastRuneInString(s[0:i])944 i -= size945 if f(r) == truth {946 return i947 }948 }949 return -1950}951 952// asciiSet is a 32-byte value, where each bit represents the presence of a953// given ASCII character in the set. The 128-bits of the lower 16 bytes,954// starting with the least-significant bit of the lowest word to the955// most-significant bit of the highest word, map to the full range of all956// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,957// ensuring that any non-ASCII character will be reported as not in the set.958// This allocates a total of 32 bytes even though the upper half959// is unused to avoid bounds checks in asciiSet.contains.960type asciiSet [8]uint32961 962// makeASCIISet creates a set of ASCII characters and reports whether all963// characters in chars are ASCII.964func makeASCIISet(chars string) (as asciiSet, ok bool) {965 for i := 0; i < len(chars); i++ {966 c := chars[i]967 if c >= utf8.RuneSelf {968 return as, false969 }970 as[c/32] |= 1 << (c % 32)971 }972 return as, true973}974 975// contains reports whether c is inside the set.976func (as *asciiSet) contains(c byte) bool {977 return (as[c/32] & (1 << (c % 32))) != 0978}979 980// Trim returns a slice of the string s with all leading and981// trailing Unicode code points contained in cutset removed.982func Trim(s, cutset string) string {983 if s == "" || cutset == "" {984 return s985 }986 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {987 return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])988 }989 if as, ok := makeASCIISet(cutset); ok {990 return trimLeftASCII(trimRightASCII(s, &as), &as)991 }992 return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)993}994 995// TrimLeft returns a slice of the string s with all leading996// Unicode code points contained in cutset removed.997//998// To remove a prefix, use [TrimPrefix] instead.999func TrimLeft(s, cutset string) string {1000 if s == "" || cutset == "" {1001 return s1002 }1003 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {1004 return trimLeftByte(s, cutset[0])1005 }1006 if as, ok := makeASCIISet(cutset); ok {1007 return trimLeftASCII(s, &as)1008 }1009 return trimLeftUnicode(s, cutset)1010}1011 1012func trimLeftByte(s string, c byte) string {1013 for len(s) > 0 && s[0] == c {1014 s = s[1:]1015 }1016 return s1017}1018 1019func trimLeftASCII(s string, as *asciiSet) string {1020 for len(s) > 0 {1021 if !as.contains(s[0]) {1022 break1023 }1024 s = s[1:]1025 }1026 return s1027}1028 1029func trimLeftUnicode(s, cutset string) string {1030 for len(s) > 0 {1031 r, n := utf8.DecodeRuneInString(s)1032 if !ContainsRune(cutset, r) {1033 break1034 }1035 s = s[n:]1036 }1037 return s1038}1039 1040// TrimRight returns a slice of the string s, with all trailing1041// Unicode code points contained in cutset removed.1042//1043// To remove a suffix, use [TrimSuffix] instead.1044func TrimRight(s, cutset string) string {1045 if s == "" || cutset == "" {1046 return s1047 }1048 if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {1049 return trimRightByte(s, cutset[0])1050 }1051 if as, ok := makeASCIISet(cutset); ok {1052 return trimRightASCII(s, &as)1053 }1054 return trimRightUnicode(s, cutset)1055}1056 1057func trimRightByte(s string, c byte) string {1058 for len(s) > 0 && s[len(s)-1] == c {1059 s = s[:len(s)-1]1060 }1061 return s1062}1063 1064func trimRightASCII(s string, as *asciiSet) string {1065 for len(s) > 0 {1066 if !as.contains(s[len(s)-1]) {1067 break1068 }1069 s = s[:len(s)-1]1070 }1071 return s1072}1073 1074func trimRightUnicode(s, cutset string) string {1075 for len(s) > 0 {1076 r, n := rune(s[len(s)-1]), 11077 if r >= utf8.RuneSelf {1078 r, n = utf8.DecodeLastRuneInString(s)1079 }1080 if !ContainsRune(cutset, r) {1081 break1082 }1083 s = s[:len(s)-n]1084 }1085 return s1086}1087 1088// TrimSpace returns a slice (substring) of the string s,1089// with all leading and trailing white space removed,1090// as defined by Unicode.1091func TrimSpace(s string) string {1092 // Fast path for ASCII: look for the first ASCII non-space byte.1093 for lo, c := range []byte(s) {1094 if c >= utf8.RuneSelf {1095 // If we run into a non-ASCII byte, fall back to the1096 // slower unicode-aware method on the remaining bytes.1097 return TrimFunc(s[lo:], unicode.IsSpace)1098 }1099 if asciiSpace[c] != 0 {1100 continue1101 }1102 s = s[lo:]1103 // Now look for the first ASCII non-space byte from the end.1104 for hi := len(s) - 1; hi >= 0; hi-- {1105 c := s[hi]1106 if c >= utf8.RuneSelf {1107 return TrimRightFunc(s[:hi+1], unicode.IsSpace)1108 }1109 if asciiSpace[c] == 0 {1110 // At this point, s[:hi+1] starts and ends with ASCII1111 // non-space bytes, so we're done. Non-ASCII cases have1112 // already been handled above.1113 return s[:hi+1]1114 }1115 }1116 }1117 return ""1118}1119 1120// TrimPrefix returns s without the provided leading prefix string.1121// If s doesn't start with prefix, s is returned unchanged.1122func TrimPrefix(s, prefix string) string {1123 return stringslite.TrimPrefix(s, prefix)1124}1125 1126// TrimSuffix returns s without the provided trailing suffix string.1127// If s doesn't end with suffix, s is returned unchanged.1128func TrimSuffix(s, suffix string) string {1129 return stringslite.TrimSuffix(s, suffix)1130}1131 1132// Replace returns a copy of the string s with the first n1133// non-overlapping instances of old replaced by new.1134// If old is empty, it matches at the beginning of the string1135// and after each UTF-8 sequence, yielding up to k+1 replacements1136// for a k-rune string.1137// If n < 0, there is no limit on the number of replacements.1138func Replace(s, old, new string, n int) string {1139 if old == new || n == 0 {1140 return s // avoid allocation1141 }1142 1143 // Compute number of replacements.1144 if m := Count(s, old); m == 0 {1145 return s // avoid allocation1146 } else if n < 0 || m < n {1147 n = m1148 }1149 1150 // Apply replacements to buffer.1151 var b Builder1152 b.Grow(len(s) + n*(len(new)-len(old)))1153 start := 01154 if len(old) > 0 {1155 for range n {1156 j := start + Index(s[start:], old)1157 b.WriteString(s[start:j])1158 b.WriteString(new)1159 start = j + len(old)1160 }1161 } else { // len(old) == 01162 b.WriteString(new)1163 for range n - 1 {1164 _, wid := utf8.DecodeRuneInString(s[start:])1165 j := start + wid1166 b.WriteString(s[start:j])1167 b.WriteString(new)1168 start = j1169 }1170 }1171 b.WriteString(s[start:])1172 return b.String()1173}1174 1175// ReplaceAll returns a copy of the string s with all1176// non-overlapping instances of old replaced by new.1177// If old is empty, it matches at the beginning of the string1178// and after each UTF-8 sequence, yielding up to k+1 replacements1179// for a k-rune string.1180func ReplaceAll(s, old, new string) string {1181 return Replace(s, old, new, -1)1182}1183 1184// EqualFold reports whether s and t, interpreted as UTF-8 strings,1185// are equal under simple Unicode case-folding, which is a more general1186// form of case-insensitivity.1187func EqualFold(s, t string) bool {1188 // ASCII fast path1189 i := 01190 for n := min(len(s), len(t)); i < n; i++ {1191 sr := s[i]1192 tr := t[i]1193 if sr|tr >= utf8.RuneSelf {1194 goto hasUnicode1195 }1196 1197 // Easy case.1198 if tr == sr {1199 continue1200 }