1 package govalidator
2
3 import (
4 "errors"
5 "fmt"
6 "html"
7 "math"
8 "path"
9 "regexp"
10 "strings"
11 "unicode"
12 "unicode/utf8"
13 )
14
15
16 func Contains(str, substring string) bool {
17 return strings.Contains(str, substring)
18 }
19
20
21
22 func Matches(str, pattern string) bool {
23 match, _ := regexp.MatchString(pattern, str)
24 return match
25 }
26
27
28
29 func LeftTrim(str, chars string) string {
30 if chars == "" {
31 return strings.TrimLeftFunc(str, unicode.IsSpace)
32 }
33 r, _ := regexp.Compile("^[" + chars + "]+")
34 return r.ReplaceAllString(str, "")
35 }
36
37
38
39 func RightTrim(str, chars string) string {
40 if chars == "" {
41 return strings.TrimRightFunc(str, unicode.IsSpace)
42 }
43 r, _ := regexp.Compile("[" + chars + "]+$")
44 return r.ReplaceAllString(str, "")
45 }
46
47
48
49 func Trim(str, chars string) string {
50 return LeftTrim(RightTrim(str, chars), chars)
51 }
52
53
54 func WhiteList(str, chars string) string {
55 pattern := "[^" + chars + "]+"
56 r, _ := regexp.Compile(pattern)
57 return r.ReplaceAllString(str, "")
58 }
59
60
61 func BlackList(str, chars string) string {
62 pattern := "[" + chars + "]+"
63 r, _ := regexp.Compile(pattern)
64 return r.ReplaceAllString(str, "")
65 }
66
67
68
69 func StripLow(str string, keepNewLines bool) string {
70 chars := ""
71 if keepNewLines {
72 chars = "\x00-\x09\x0B\x0C\x0E-\x1F\x7F"
73 } else {
74 chars = "\x00-\x1F\x7F"
75 }
76 return BlackList(str, chars)
77 }
78
79
80 func ReplacePattern(str, pattern, replace string) string {
81 r, _ := regexp.Compile(pattern)
82 return r.ReplaceAllString(str, replace)
83 }
84
85
86 var Escape = html.EscapeString
87
88 func addSegment(inrune, segment []rune) []rune {
89 if len(segment) == 0 {
90 return inrune
91 }
92 if len(inrune) != 0 {
93 inrune = append(inrune, '_')
94 }
95 inrune = append(inrune, segment...)
96 return inrune
97 }
98
99
100
101 func UnderscoreToCamelCase(s string) string {
102 return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1)
103 }
104
105
106
107 func CamelCaseToUnderscore(str string) string {
108 var output []rune
109 var segment []rune
110 for _, r := range str {
111
112
113 if !unicode.IsLower(r) && string(r) != "_" && !unicode.IsNumber(r) {
114 output = addSegment(output, segment)
115 segment = nil
116 }
117 segment = append(segment, unicode.ToLower(r))
118 }
119 output = addSegment(output, segment)
120 return string(output)
121 }
122
123
124 func Reverse(s string) string {
125 r := []rune(s)
126 for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
127 r[i], r[j] = r[j], r[i]
128 }
129 return string(r)
130 }
131
132
133 func GetLines(s string) []string {
134 return strings.Split(s, "\n")
135 }
136
137
138 func GetLine(s string, index int) (string, error) {
139 lines := GetLines(s)
140 if index < 0 || index >= len(lines) {
141 return "", errors.New("line index out of bounds")
142 }
143 return lines[index], nil
144 }
145
146
147 func RemoveTags(s string) string {
148 return ReplacePattern(s, "<[^>]*>", "")
149 }
150
151
152 func SafeFileName(str string) string {
153 name := strings.ToLower(str)
154 name = path.Clean(path.Base(name))
155 name = strings.Trim(name, " ")
156 separators, err := regexp.Compile(`[ &_=+:]`)
157 if err == nil {
158 name = separators.ReplaceAllString(name, "-")
159 }
160 legal, err := regexp.Compile(`[^[:alnum:]-.]`)
161 if err == nil {
162 name = legal.ReplaceAllString(name, "")
163 }
164 for strings.Contains(name, "--") {
165 name = strings.Replace(name, "--", "-", -1)
166 }
167 return name
168 }
169
170
171
172
173
174
175
176 func NormalizeEmail(str string) (string, error) {
177 if !IsEmail(str) {
178 return "", fmt.Errorf("%s is not an email", str)
179 }
180 parts := strings.Split(str, "@")
181 parts[0] = strings.ToLower(parts[0])
182 parts[1] = strings.ToLower(parts[1])
183 if parts[1] == "gmail.com" || parts[1] == "googlemail.com" {
184 parts[1] = "gmail.com"
185 parts[0] = strings.Split(ReplacePattern(parts[0], `\.`, ""), "+")[0]
186 }
187 return strings.Join(parts, "@"), nil
188 }
189
190
191 func Truncate(str string, length int, ending string) string {
192 var aftstr, befstr string
193 if len(str) > length {
194 words := strings.Fields(str)
195 before, present := 0, 0
196 for i := range words {
197 befstr = aftstr
198 before = present
199 aftstr = aftstr + words[i] + " "
200 present = len(aftstr)
201 if present > length && i != 0 {
202 if (length - before) < (present - length) {
203 return Trim(befstr, " /\\.,\"'#!?&@+-") + ending
204 }
205 return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending
206 }
207 }
208 }
209
210 return str
211 }
212
213
214 func PadLeft(str string, padStr string, padLen int) string {
215 return buildPadStr(str, padStr, padLen, true, false)
216 }
217
218
219 func PadRight(str string, padStr string, padLen int) string {
220 return buildPadStr(str, padStr, padLen, false, true)
221 }
222
223
224 func PadBoth(str string, padStr string, padLen int) string {
225 return buildPadStr(str, padStr, padLen, true, true)
226 }
227
228
229
230 func buildPadStr(str string, padStr string, padLen int, padLeft bool, padRight bool) string {
231
232
233 if padLen < utf8.RuneCountInString(str) {
234 return str
235 }
236
237 padLen -= utf8.RuneCountInString(str)
238
239 targetLen := padLen
240
241 targetLenLeft := targetLen
242 targetLenRight := targetLen
243 if padLeft && padRight {
244 targetLenLeft = padLen / 2
245 targetLenRight = padLen - targetLenLeft
246 }
247
248 strToRepeatLen := utf8.RuneCountInString(padStr)
249
250 repeatTimes := int(math.Ceil(float64(targetLen) / float64(strToRepeatLen)))
251 repeatedString := strings.Repeat(padStr, repeatTimes)
252
253 leftSide := ""
254 if padLeft {
255 leftSide = repeatedString[0:targetLenLeft]
256 }
257
258 rightSide := ""
259 if padRight {
260 rightSide = repeatedString[0:targetLenRight]
261 }
262
263 return leftSide + str + rightSide
264 }
265
266
267 func TruncatingErrorf(str string, args ...interface{}) error {
268 n := strings.Count(str, "%s")
269 return fmt.Errorf(str, args[:n]...)
270 }
271
View as plain text