-
Notifications
You must be signed in to change notification settings - Fork 18
/
stringy.go
405 lines (367 loc) · 13.1 KB
/
stringy.go
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
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
package stringy
import (
"errors"
"math"
"math/rand"
"regexp"
"strings"
"time"
"unicode"
)
var matchWordRegexp = regexp.MustCompile(`[\s]*[\W]\pN`)
// input is struct that holds input from user and result
type input struct {
Input string
Result string
}
// StringManipulation is an interface that holds all abstract methods to manipulate strings
type StringManipulation interface {
Acronym() StringManipulation
Between(start, end string) StringManipulation
Boolean() bool
PascalCase(rule ...string) StringManipulation
CamelCase(rule ...string) StringManipulation
ContainsAll(check ...string) bool
Delimited(delimiter string, rule ...string) StringManipulation
First(length int) string
Get() string
KebabCase(rule ...string) StringManipulation
Last(length int) string
LcFirst() string
Lines() []string
Pad(length int, with, padType string) string
RemoveSpecialCharacter() string
ReplaceFirst(search, replace string) string
ReplaceLast(search, replace string) string
Reverse() string
Shuffle() string
Surround(with string) string
SnakeCase(rule ...string) StringManipulation
Tease(length int, indicator string) string
Title() string
ToLower() string
ToUpper() string
UcFirst() string
Prefix(with string) string
Suffix(with string) string
}
// New func returns pointer to input struct
func New(val string) StringManipulation {
return &input{Input: val}
}
// Acronym func returns acronym of input string.
// You can chain to upper which with make result all upercase or ToLower
// which will make result all lower case or Get which will return result as it is
func (i *input) Acronym() StringManipulation {
input := getInput(*i)
words := strings.Fields(input)
var acronym string
for _, word := range words {
acronym += string(word[0])
}
i.Result = acronym
return i
}
// Between takes two string params start and end which and returns
// value which is in middle of start and end part of input. You can
// chain to upper which with make result all upercase or ToLower which
// will make result all lower case or Get which will return result as it is
func (i *input) Between(start, end string) StringManipulation {
if (start == "" && end == "") || i.Input == "" {
return i
}
input := strings.ToLower(i.Input)
lcStart := strings.ToLower(start)
lcEnd := strings.ToLower(end)
var startIndex, endIndex int
if len(start) > 0 && strings.Contains(input, lcStart) {
startIndex = len(start)
}
if len(end) > 0 && strings.Contains(input, lcEnd) {
endIndex = strings.Index(input, lcEnd)
} else if len(input) > 0 {
endIndex = len(input)
}
i.Result = strings.TrimSpace(i.Input[startIndex:endIndex])
return i
}
// Boolean func returns boolean value of string value like on, off, 0, 1, yes, no
// returns boolean value of string input. You can chain this function on other function
// which returns implemented StringManipulation interface
func (i *input) Boolean() bool {
input := getInput(*i)
inputLower := strings.ToLower(input)
off := contains(False, inputLower)
if off {
return false
}
on := contains(True, inputLower)
if on {
return true
}
panic(errors.New(InvalidLogicalString))
}
// CamelCase is variadic function which takes one Param rule i.e slice of strings and it returns
// input type string in camel case form and rule helps to omit character you want to omit from string.
// By default special characters like "_", "-","."," " are l\treated like word separator and treated
// accordingly by default and you don't have to worry about it
// First letter will be lowercase.
// Example input: hello user
// Result : helloUser
func (i *input) CamelCase(rule ...string) StringManipulation {
input := getInput(*i)
// removing excess space
wordArray := caseHelper(input, true, rule...)
for i, word := range wordArray {
if i == 0 {
wordArray[i] = strings.ToLower(word)
} else {
wordArray[i] = ucfirst(word)
}
}
i.Result = strings.Join(wordArray, "")
return i
}
// PascalCase is variadic function which takes one Param rule i.e slice of strings and it returns
// input type string in camel case form and rule helps to omit character you want to omit from string.
// By default special characters like "_", "-","."," " are l\treated like word separator and treated
// accordingly by default and you don't have to worry about it
// Example input: hello user
// Result : HelloUser
func (i *input) PascalCase(rule ...string) StringManipulation {
input := getInput(*i)
// removing excess space
wordArray := caseHelper(input, true, rule...)
for i, word := range wordArray {
wordArray[i] = ucfirst(word)
}
i.Result = strings.Join(wordArray, "")
return i
}
// ContainsAll is variadic function which takes slice of strings as param and checks if they are present
// in input and returns boolean value accordingly
func (i *input) ContainsAll(check ...string) bool {
input := getInput(*i)
for _, item := range check {
if !strings.Contains(input, item) {
return false
}
}
return true
}
// Delimited is variadic function that takes two params delimiter and slice of strings i.e rule. It joins
// the string by passed delimeter. Rule param helps to omit character you want to omit from string. By
// default special characters like "_", "-","."," " are l\treated like word separator and treated accordingly
// by default and you dont have to worry about it.
func (i *input) Delimited(delimiter string, rule ...string) StringManipulation {
input := getInput(*i)
if strings.TrimSpace(delimiter) == "" {
delimiter = "."
}
wordArray := caseHelper(input, false, rule...)
i.Result = strings.Join(wordArray, delimiter)
return i
}
// First returns first n characters from provided input. It removes all spaces in string before doing so.
func (i *input) First(length int) string {
input := getInput(*i)
input = strings.ReplaceAll(input, " ", "")
if len(input) < length {
panic(errors.New(LengthError))
}
return input[0:length]
}
// Get simply returns result and can be chained on function which
// returns StringManipulation interface
func (i *input) Get() string {
return getInput(*i)
}
// KebabCase is variadic function that takes one Param slice of strings named rule and it returns passed string
// in kebab case form. Rule param helps to omit character you want to omit from string. By default special characters
// like "_", "-","."," " are l\treated like word separator and treated accordingly by default and you dont have to worry
// about it. If you don't want to omit any character pass nothing.
// Example input: hello user
// Result : hello-user
func (i *input) KebabCase(rule ...string) StringManipulation {
input := getInput(*i)
wordArray := caseHelper(input, false, rule...)
i.Result = strings.Join(wordArray, "-")
return i
}
// Last returns last n characters from provided input. It removes all spaces in string before doing so.
func (i *input) Last(length int) string {
input := getInput(*i)
input = strings.ReplaceAll(input, " ", "")
inputLen := len(input)
if len(input) < length {
panic(errors.New(LengthError))
}
start := inputLen - length
return input[start:inputLen]
}
// LcFirst simply returns result by lower casing first letter of string and it can be chained on
// function which return StringManipulation interface
func (i *input) LcFirst() string {
input := getInput(*i)
for _, v := range input {
return string(unicode.ToLower(v)) + input[len(string(v)):]
}
return ""
}
// Lines returns slice of strings by removing white space characters
func (i *input) Lines() []string {
input := getInput(*i)
result := matchWordRegexp.ReplaceAllString(input, " ")
return strings.Fields(strings.TrimSpace(result))
}
// Pad takes three param length i.e total length to be after padding, with i.e what to pad
// with and pad type which can be ("both" or "left" or "right") it return string after padding
// upto length by with param and on padType type it can be chained on function which return
// StringManipulation interface
func (i *input) Pad(length int, with, padType string) string {
input := getInput(*i)
inputLength := len(input)
padLength := len(with)
if inputLength >= length {
return input
}
switch padType {
case Right:
var count = 1 + ((length - padLength) / padLength)
var result = input + strings.Repeat(with, count)
return result[:length]
case Left:
var count = 1 + ((length - padLength) / padLength)
var result = strings.Repeat(with, count) + input
return result[(len(result) - length):]
case Both:
length := (float64(length - inputLength)) / float64(2)
repeat := math.Ceil(length / float64(padLength))
return strings.Repeat(with, int(repeat))[:int(math.Floor(float64(length)))] + input + strings.Repeat(with, int(repeat))[:int(math.Ceil(float64(length)))]
default:
return input
}
}
// RemoveSpecialCharacter removes all special characters and returns the string
// it can be chained on function which return StringManipulation interface
func (i *input) RemoveSpecialCharacter() string {
input := getInput(*i)
var result strings.Builder
for i := 0; i < len(input); i++ {
b := input[i]
if ('a' <= b && b <= 'z') ||
('A' <= b && b <= 'Z') ||
('0' <= b && b <= '9') ||
b == ' ' {
result.WriteByte(b)
}
}
return result.String()
}
// ReplaceFirst takes two param search and replace. It returns string by searching search
// sub string and replacing it with replace substring on first occurrence it can be chained
// on function which return StringManipulation interface.
func (i *input) ReplaceFirst(search, replace string) string {
input := getInput(*i)
return replaceStr(input, search, replace, First)
}
// ReplaceLast takes two param search and replace
// it return string by searching search sub string and replacing it
// with replace substring on last occurrence
// it can be chained on function which return StringManipulation interface
func (i *input) ReplaceLast(search, replace string) string {
input := getInput(*i)
return replaceStr(input, search, replace, Last)
}
// Reverse reverses the passed strings
// it can be chained on function which return StringManipulation interface
func (i *input) Reverse() string {
input := getInput(*i)
r := []rune(input)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
// Shuffle shuffles the given string randomly
// it can be chained on function which return StringManipulation interface
func (i *input) Shuffle() string {
input := getInput(*i)
rand.Seed(time.Now().Unix())
inRune := []rune(input)
rand.Shuffle(len(inRune), func(i, j int) {
inRune[i], inRune[j] = inRune[j], inRune[i]
})
return string(inRune)
}
// SnakeCase is variadic function that takes one Param slice of strings named rule
// and it returns passed string in snake case form. Rule param helps to omit character
// you want to omit from string. By default special characters like "_", "-","."," " are treated
// like word separator and treated accordingly by default and you don't have to worry about it.
// If you don't want to omit any character pass nothing.
func (i *input) SnakeCase(rule ...string) StringManipulation {
input := getInput(*i)
wordArray := caseHelper(input, false, rule...)
i.Result = strings.Join(wordArray, "_")
return i
}
// Surround takes one param with which is used to surround user input and it
// can be chained on function which return StringManipulation interface.
func (i *input) Surround(with string) string {
input := getInput(*i)
return with + input + with
}
// Tease takes two params length and indicator and it shortens given string
// on passed length and adds indicator on end
// it can be chained on function which return StringManipulation interface
func (i *input) Tease(length int, indicator string) string {
input := getInput(*i)
if input == "" || len(input) < length {
return input
}
return input[:length] + indicator
}
// ToLower makes all string of user input to lowercase
// it can be chained on function which return StringManipulation interface
func (i *input) ToLower() (result string) {
input := getInput(*i)
return strings.ToLower(input)
}
// Title makes first letter of each word of user input to uppercase
// it can be chained on function which return StringManipulation interface
func (i *input) Title() (result string) {
input := getInput(*i)
wordArray := strings.Split(input, " ")
for i, word := range wordArray {
wordArray[i] = strings.ToUpper(string(word[0])) + strings.ToLower(word[1:])
}
return strings.Join(wordArray, " ")
}
// ToUpper makes all string of user input to uppercase
// it can be chained on function which return StringManipulation interface
func (i *input) ToUpper() string {
input := getInput(*i)
return strings.ToUpper(input)
}
// UcFirst makes first word of user input to uppercase
// it can be chained on function which return StringManipulation interface
func (i *input) UcFirst() string {
input := getInput(*i)
return ucfirst(input)
}
// Prefix makes sure that string is prefixed with a given string
func (i *input) Prefix(with string) string {
input := getInput(*i)
if strings.HasPrefix(input, with) {
return input
}
return with + input
}
// Suffix makes sure that string is suffixed with a given string
func (i *input) Suffix(with string) string {
input := getInput(*i)
if strings.HasSuffix(input, with) {
return input
}
return input + with
}