1package str 2 3import ( 4 "fmt" 5 "html" 6 //"log" 7 "regexp" 8 "strings" 9) 10 11// Verbose flag enables console output for those functions that have 12// counterparts in Go's excellent stadard packages. 13var Verbose = false 14var templateOpen = "{{" 15var templateClose = "}}" 16 17var beginEndSpacesRe = regexp.MustCompile("^\\s+|\\s+$") 18var camelizeRe = regexp.MustCompile(`(\-|_|\s)+(.)?`) 19var camelizeRe2 = regexp.MustCompile(`(\-|_|\s)+`) 20var capitalsRe = regexp.MustCompile("([A-Z])") 21var dashSpaceRe = regexp.MustCompile(`[-\s]+`) 22var dashesRe = regexp.MustCompile("-+") 23var isAlphaNumericRe = regexp.MustCompile(`[^0-9a-z\xC0-\xFF]`) 24var isAlphaRe = regexp.MustCompile(`[^a-z\xC0-\xFF]`) 25var nWhitespaceRe = regexp.MustCompile(`\s+`) 26var notDigitsRe = regexp.MustCompile(`[^0-9]`) 27var slugifyRe = regexp.MustCompile(`[^\w\s\-]`) 28var spaceUnderscoreRe = regexp.MustCompile("[_\\s]+") 29var spacesRe = regexp.MustCompile("[\\s\\xA0]+") 30var stripPuncRe = regexp.MustCompile(`[^\w\s]|_`) 31var templateRe = regexp.MustCompile(`([\-\[\]()*\s])`) 32var templateRe2 = regexp.MustCompile(`\$`) 33var underscoreRe = regexp.MustCompile(`([a-z\d])([A-Z]+)`) 34var whitespaceRe = regexp.MustCompile(`^[\s\xa0]*$`) 35 36func min(a, b int) int { 37 if a < b { 38 return a 39 } 40 return b 41} 42 43func max(a, b int) int { 44 if a > b { 45 return a 46 } 47 return b 48} 49 50// Between extracts a string between left and right strings. 51func Between(s, left, right string) string { 52 l := len(left) 53 startPos := strings.Index(s, left) 54 if startPos < 0 { 55 return "" 56 } 57 endPos := IndexOf(s, right, startPos+l) 58 //log.Printf("%s: left %s right %s start %d end %d", s, left, right, startPos+l, endPos) 59 if endPos < 0 { 60 return "" 61 } else if right == "" { 62 return s[endPos:] 63 } else { 64 return s[startPos+l : endPos] 65 } 66} 67 68// BetweenF is the filter form for Between. 69func BetweenF(left, right string) func(string) string { 70 return func(s string) string { 71 return Between(s, left, right) 72 } 73} 74 75// Camelize return new string which removes any underscores or dashes and convert a string into camel casing. 76func Camelize(s string) string { 77 return camelizeRe.ReplaceAllStringFunc(s, func(val string) string { 78 val = strings.ToUpper(val) 79 val = camelizeRe2.ReplaceAllString(val, "") 80 return val 81 }) 82} 83 84// Capitalize uppercases the first char of s and lowercases the rest. 85func Capitalize(s string) string { 86 return strings.ToUpper(s[0:1]) + strings.ToLower(s[1:]) 87} 88 89// CharAt returns a string from the character at the specified position. 90func CharAt(s string, index int) string { 91 l := len(s) 92 shortcut := index < 0 || index > l-1 || l == 0 93 if shortcut { 94 return "" 95 } 96 return s[index : index+1] 97} 98 99// CharAtF is the filter form of CharAt. 100func CharAtF(index int) func(string) string { 101 return func(s string) string { 102 return CharAt(s, index) 103 } 104} 105 106// ChompLeft removes prefix at the start of a string. 107func ChompLeft(s, prefix string) string { 108 if strings.HasPrefix(s, prefix) { 109 return s[len(prefix):] 110 } 111 return s 112} 113 114// ChompLeftF is the filter form of ChompLeft. 115func ChompLeftF(prefix string) func(string) string { 116 return func(s string) string { 117 return ChompLeft(s, prefix) 118 } 119} 120 121// ChompRight removes suffix from end of s. 122func ChompRight(s, suffix string) string { 123 if strings.HasSuffix(s, suffix) { 124 return s[:len(s)-len(suffix)] 125 } 126 return s 127} 128 129// ChompRightF is the filter form of ChompRight. 130func ChompRightF(suffix string) func(string) string { 131 return func(s string) string { 132 return ChompRight(s, suffix) 133 } 134} 135 136// Classify returns a camelized string with the first letter upper cased. 137func Classify(s string) string { 138 return Camelize("-" + s) 139} 140 141// ClassifyF is the filter form of Classify. 142func ClassifyF(s string) func(string) string { 143 return func(s string) string { 144 return Classify(s) 145 } 146} 147 148// Clean compresses all adjacent whitespace to a single space and trims s. 149func Clean(s string) string { 150 s = spacesRe.ReplaceAllString(s, " ") 151 s = beginEndSpacesRe.ReplaceAllString(s, "") 152 return s 153} 154 155// Dasherize converts a camel cased string into a string delimited by dashes. 156func Dasherize(s string) string { 157 s = strings.TrimSpace(s) 158 s = spaceUnderscoreRe.ReplaceAllString(s, "-") 159 s = capitalsRe.ReplaceAllString(s, "-$1") 160 s = dashesRe.ReplaceAllString(s, "-") 161 s = strings.ToLower(s) 162 return s 163} 164 165// EscapeHTML is alias for html.EscapeString. 166func EscapeHTML(s string) string { 167 if Verbose { 168 fmt.Println("Use html.EscapeString instead of EscapeHTML") 169 } 170 return html.EscapeString(s) 171} 172 173// DecodeHTMLEntities decodes HTML entities into their proper string representation. 174// DecodeHTMLEntities is an alias for html.UnescapeString 175func DecodeHTMLEntities(s string) string { 176 if Verbose { 177 fmt.Println("Use html.UnescapeString instead of DecodeHTMLEntities") 178 } 179 return html.UnescapeString(s) 180} 181 182// EnsurePrefix ensures s starts with prefix. 183func EnsurePrefix(s, prefix string) string { 184 if strings.HasPrefix(s, prefix) { 185 return s 186 } 187 return prefix + s 188} 189 190// EnsurePrefixF is the filter form of EnsurePrefix. 191func EnsurePrefixF(prefix string) func(string) string { 192 return func(s string) string { 193 return EnsurePrefix(s, prefix) 194 } 195} 196 197// EnsureSuffix ensures s ends with suffix. 198func EnsureSuffix(s, suffix string) string { 199 if strings.HasSuffix(s, suffix) { 200 return s 201 } 202 return s + suffix 203} 204 205// EnsureSuffixF is the filter form of EnsureSuffix. 206func EnsureSuffixF(suffix string) func(string) string { 207 return func(s string) string { 208 return EnsureSuffix(s, suffix) 209 } 210} 211 212// Humanize transforms s into a human friendly form. 213func Humanize(s string) string { 214 if s == "" { 215 return s 216 } 217 s = Underscore(s) 218 var humanizeRe = regexp.MustCompile(`_id$`) 219 s = humanizeRe.ReplaceAllString(s, "") 220 s = strings.Replace(s, "_", " ", -1) 221 s = strings.TrimSpace(s) 222 s = Capitalize(s) 223 return s 224} 225 226// Iif is short for immediate if. If condition is true return truthy else falsey. 227func Iif(condition bool, truthy string, falsey string) string { 228 if condition { 229 return truthy 230 } 231 return falsey 232} 233 234// IndexOf finds the index of needle in s starting from start. 235func IndexOf(s string, needle string, start int) int { 236 l := len(s) 237 if needle == "" { 238 if start < 0 { 239 return 0 240 } else if start < l { 241 return start 242 } else { 243 return l 244 } 245 } 246 if start < 0 || start > l-1 { 247 return -1 248 } 249 pos := strings.Index(s[start:], needle) 250 if pos == -1 { 251 return -1 252 } 253 return start + pos 254} 255 256// IsAlpha returns true if a string contains only letters from ASCII (a-z,A-Z). Other letters from other languages are not supported. 257func IsAlpha(s string) bool { 258 return !isAlphaRe.MatchString(strings.ToLower(s)) 259} 260 261// IsAlphaNumeric returns true if a string contains letters and digits. 262func IsAlphaNumeric(s string) bool { 263 return !isAlphaNumericRe.MatchString(strings.ToLower(s)) 264} 265 266// IsLower returns true if s comprised of all lower case characters. 267func IsLower(s string) bool { 268 return IsAlpha(s) && s == strings.ToLower(s) 269} 270 271// IsNumeric returns true if a string contains only digits from 0-9. Other digits not in Latin (such as Arabic) are not currently supported. 272func IsNumeric(s string) bool { 273 return !notDigitsRe.MatchString(s) 274} 275 276// IsUpper returns true if s contains all upper case chracters. 277func IsUpper(s string) bool { 278 return IsAlpha(s) && s == strings.ToUpper(s) 279} 280 281// IsEmpty returns true if the string is solely composed of whitespace. 282func IsEmpty(s string) bool { 283 if s == "" { 284 return true 285 } 286 return whitespaceRe.MatchString(s) 287} 288 289// Left returns the left substring of length n. 290func Left(s string, n int) string { 291 if n < 0 { 292 return Right(s, -n) 293 } 294 return Substr(s, 0, n) 295} 296 297// LeftF is the filter form of Left. 298func LeftF(n int) func(string) string { 299 return func(s string) string { 300 return Left(s, n) 301 } 302} 303 304// LeftOf returns the substring left of needle. 305func LeftOf(s string, needle string) string { 306 return Between(s, "", needle) 307} 308 309// Letters returns an array of runes as strings so it can be indexed into. 310func Letters(s string) []string { 311 result := []string{} 312 for _, r := range s { 313 result = append(result, string(r)) 314 } 315 return result 316} 317 318// Lines convert windows newlines to unix newlines then convert to an Array of lines. 319func Lines(s string) []string { 320 s = strings.Replace(s, "\r\n", "\n", -1) 321 return strings.Split(s, "\n") 322} 323 324// Map maps an array's iitem through an iterator. 325func Map(arr []string, iterator func(string) string) []string { 326 r := []string{} 327 for _, item := range arr { 328 r = append(r, iterator(item)) 329 } 330 return r 331} 332 333// Match returns true if patterns matches the string 334func Match(s, pattern string) bool { 335 r := regexp.MustCompile(pattern) 336 return r.MatchString(s) 337} 338