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