github.com/solo-io/cue@v0.4.7/internal/str/str.go (about) 1 // Copyright 2018 The CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package str provides string manipulation utilities. 16 package str // import "github.com/solo-io/cue/internal/str" 17 18 import ( 19 "bytes" 20 "fmt" 21 "unicode" 22 "unicode/utf8" 23 ) 24 25 // StringList flattens its arguments into a single []string. 26 // Each argument in args must have type string or []string. 27 func StringList(args ...interface{}) []string { 28 var x []string 29 for _, arg := range args { 30 switch arg := arg.(type) { 31 case []string: 32 x = append(x, arg...) 33 case string: 34 x = append(x, arg) 35 default: 36 panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg)) 37 } 38 } 39 return x 40 } 41 42 // ToFold returns a string with the property that 43 // strings.EqualFold(s, t) iff ToFold(s) == ToFold(t) 44 // This lets us test a large set of strings for fold-equivalent 45 // duplicates without making a quadratic number of calls 46 // to EqualFold. Note that strings.ToUpper and strings.ToLower 47 // do not have the desired property in some corner cases. 48 func ToFold(s string) string { 49 // Fast path: all ASCII, no upper case. 50 // Most paths look like this already. 51 for i := 0; i < len(s); i++ { 52 c := s[i] 53 if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' { 54 goto Slow 55 } 56 } 57 return s 58 59 Slow: 60 var buf bytes.Buffer 61 for _, r := range s { 62 // SimpleFold(x) cycles to the next equivalent rune > x 63 // or wraps around to smaller values. Iterate until it wraps, 64 // and we've found the minimum value. 65 for { 66 r0 := r 67 r = unicode.SimpleFold(r0) 68 if r <= r0 { 69 break 70 } 71 } 72 // Exception to allow fast path above: A-Z => a-z 73 if 'A' <= r && r <= 'Z' { 74 r += 'a' - 'A' 75 } 76 buf.WriteRune(r) 77 } 78 return buf.String() 79 } 80 81 // FoldDup reports a pair of strings from the list that are 82 // equal according to strings.EqualFold. 83 // It returns "", "" if there are no such strings. 84 func FoldDup(list []string) (string, string) { 85 clash := map[string]string{} 86 for _, s := range list { 87 fold := ToFold(s) 88 if t := clash[fold]; t != "" { 89 if s > t { 90 s, t = t, s 91 } 92 return s, t 93 } 94 clash[fold] = s 95 } 96 return "", "" 97 } 98 99 // Contains reports whether x contains s. 100 func Contains(x []string, s string) bool { 101 for _, t := range x { 102 if t == s { 103 return true 104 } 105 } 106 return false 107 } 108 109 func isSpaceByte(c byte) bool { 110 return c == ' ' || c == '\t' || c == '\n' || c == '\r' 111 } 112 113 // SplitQuotedFields splits s into a list of fields, 114 // allowing single or double quotes around elements. 115 // There is no unescaping or other processing within 116 // quoted fields. 117 func SplitQuotedFields(s string) ([]string, error) { 118 // Split fields allowing '' or "" around elements. 119 // Quotes further inside the string do not count. 120 var f []string 121 for len(s) > 0 { 122 for len(s) > 0 && isSpaceByte(s[0]) { 123 s = s[1:] 124 } 125 if len(s) == 0 { 126 break 127 } 128 // Accepted quoted string. No unescaping inside. 129 if s[0] == '"' || s[0] == '\'' { 130 quote := s[0] 131 s = s[1:] 132 i := 0 133 for i < len(s) && s[i] != quote { 134 i++ 135 } 136 if i >= len(s) { 137 return nil, fmt.Errorf("unterminated %c string", quote) 138 } 139 f = append(f, s[:i]) 140 s = s[i+1:] 141 continue 142 } 143 i := 0 144 for i < len(s) && !isSpaceByte(s[i]) { 145 i++ 146 } 147 f = append(f, s[:i]) 148 s = s[i:] 149 } 150 return f, nil 151 }