github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/str/str.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package str provides string manipulation utilities. 6 package str 7 8 import ( 9 "fmt" 10 "strings" 11 "unicode" 12 "unicode/utf8" 13 ) 14 15 // StringList flattens its arguments into a single []string. 16 // Each argument in args must have type string or []string. 17 func StringList(args ...any) []string { 18 var x []string 19 for _, arg := range args { 20 switch arg := arg.(type) { 21 case []string: 22 x = append(x, arg...) 23 case string: 24 x = append(x, arg) 25 default: 26 panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg)) 27 } 28 } 29 return x 30 } 31 32 // ToFold returns a string with the property that 33 // 34 // strings.EqualFold(s, t) iff ToFold(s) == ToFold(t) 35 // 36 // This lets us test a large set of strings for fold-equivalent 37 // duplicates without making a quadratic number of calls 38 // to EqualFold. Note that strings.ToUpper and strings.ToLower 39 // do not have the desired property in some corner cases. 40 func ToFold(s string) string { 41 // Fast path: all ASCII, no upper case. 42 // Most paths look like this already. 43 for i := 0; i < len(s); i++ { 44 c := s[i] 45 if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' { 46 goto Slow 47 } 48 } 49 return s 50 51 Slow: 52 var b strings.Builder 53 for _, r := range s { 54 // SimpleFold(x) cycles to the next equivalent rune > x 55 // or wraps around to smaller values. Iterate until it wraps, 56 // and we've found the minimum value. 57 for { 58 r0 := r 59 r = unicode.SimpleFold(r0) 60 if r <= r0 { 61 break 62 } 63 } 64 // Exception to allow fast path above: A-Z => a-z 65 if 'A' <= r && r <= 'Z' { 66 r += 'a' - 'A' 67 } 68 b.WriteRune(r) 69 } 70 return b.String() 71 } 72 73 // FoldDup reports a pair of strings from the list that are 74 // equal according to strings.EqualFold. 75 // It returns "", "" if there are no such strings. 76 func FoldDup(list []string) (string, string) { 77 clash := map[string]string{} 78 for _, s := range list { 79 fold := ToFold(s) 80 if t := clash[fold]; t != "" { 81 if s > t { 82 s, t = t, s 83 } 84 return s, t 85 } 86 clash[fold] = s 87 } 88 return "", "" 89 } 90 91 // Contains reports whether x contains s. 92 func Contains(x []string, s string) bool { 93 for _, t := range x { 94 if t == s { 95 return true 96 } 97 } 98 return false 99 } 100 101 // Uniq removes consecutive duplicate strings from ss. 102 func Uniq(ss *[]string) { 103 if len(*ss) <= 1 { 104 return 105 } 106 uniq := (*ss)[:1] 107 for _, s := range *ss { 108 if s != uniq[len(uniq)-1] { 109 uniq = append(uniq, s) 110 } 111 } 112 *ss = uniq 113 }