github.com/seeker-insurance/kit@v0.0.13/str/str.go (about) 1 //Package str contains various tools for manipulation of strings beyond those available in golang's `strings` library. it also conatains a wide variety of string constants. 2 package str 3 4 import ( 5 "bytes" 6 "fmt" 7 "strings" 8 9 "github.com/seeker-insurance/kit/runeset" 10 ) 11 12 //RemoveRunes removes any runes listed from the string. 13 //Note that this converts to runes and back to UTF-8, so RemoveRunes(s) == s 14 //does not necessarially hold, since the code points may differ. 15 func RemoveRunes(s string, toRemove ...rune) string { 16 buf := bytes.Buffer{} 17 set := runeset.FromRunes(toRemove...) 18 for _, r := range s { 19 if !set.Contains(r) { 20 buf.WriteRune(r) 21 } 22 } 23 return buf.String() 24 } 25 26 //RemoveWhiteSpace is an alias for RemoveASCIIWhiteSpace. 27 var RemoveWhiteSpace = RemoveASCIIWhiteSpace 28 29 //RuneDiff represents a difference in runes between two []rune. 30 type RuneDiff struct { 31 a, b rune 32 position int 33 } 34 35 func (rd RuneDiff) String() string { 36 return fmt.Sprintf(`(%s, %s)`, subIfNoChar(rd.a), subIfNoChar(rd.b)) 37 } 38 39 func subIfNoChar(r rune) string { 40 if r == noChar { 41 return "NO_CHAR" 42 } 43 return string(r) 44 } 45 46 //Diffs represents a difference in runes between strings. 47 type Diffs []RuneDiff 48 49 func (d Diffs) String() string { 50 strs := make([]string, len(d)) 51 for i, rd := range d { 52 strs[i] = rd.String() 53 } 54 return fmt.Sprintf("[%s]", strings.Join(strs, ", ")) 55 56 } 57 58 //noCharacter is an code point from the unicode private use block which we use to represent one part of a diff having no character. 59 const noChar rune = '\uE011' 60 61 //RuneDiff returns a list of the differing rune-pairs in a string 62 func runeDiff(s, q []rune) Diffs { 63 var diffs Diffs 64 short := min(len(s), len(q)) 65 for i := 0; i < short; i++ { 66 c, d := s[i], q[i] 67 if c != d { 68 diffs = append(diffs, RuneDiff{c, d, i}) 69 } 70 } 71 if len(s) == short { 72 for i, d := range q[short:] { 73 diffs = append(diffs, RuneDiff{a: noChar, b: d, position: short + i}) 74 } 75 } else { 76 for i, c := range s[short:] { 77 diffs = append(diffs, RuneDiff{a: c, b: noChar, position: short + i}) 78 } 79 } 80 return diffs 81 } 82 83 //Diff compares the runes in the string for differences. Call Diff.String() for a pretty-printed list. 84 //Diff(a, b) == null if there is no difference. 85 func Diff(a, b string) Diffs { 86 return runeDiff([]rune(a), []rune(b)) 87 } 88 89 func min(a, b int) int { 90 if a < b { 91 return a 92 } 93 return b 94 } 95 96 //Map a function over a slice, returning a slice containing f(s) for s in a. 97 func Map(f func(string) string, a []string) []string { 98 mapped := make([]string, len(a)) 99 for i, s := range a { 100 mapped[i] = f(s) 101 } 102 return mapped 103 } 104 105 //Trim a string to n runes, adding a filler (if any) to show that it has been trimmed. 106 func Trim(s string, n int, filler string) string { 107 r := []rune(s) 108 if len(r) <= n { 109 return s 110 } 111 return string(r[:n]) + filler 112 } 113 114 //ContainsAny returns true if strings.Contains(s, sub) is true for any sub in subStrs. ContainsAny(s) is false. 115 func ContainsAny(s string, subStrs ...string) bool { 116 for _, sub := range subStrs { 117 if strings.Contains(s, sub) { 118 return true 119 } 120 } 121 return false 122 } 123 124 //ContainsAll returns true if strings.Contains(s, sub) is true for all sub in subStrs. ContainsAll(s) is true. 125 func ContainsAll(s string, subStrs ...string) bool { 126 for _, sub := range subStrs { 127 if !strings.Contains(s, sub) { 128 return false 129 } 130 } 131 return true 132 }