2020-04-05 16:10:08 +03:00
|
|
|
package stringy
|
2020-04-05 12:11:56 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"math"
|
|
|
|
"math/rand"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
"unicode"
|
|
|
|
)
|
|
|
|
|
2021-11-09 06:36:17 +03:00
|
|
|
// input is struct that holds input from user and result
|
2020-04-05 12:11:56 +03:00
|
|
|
type input struct {
|
|
|
|
Input string
|
|
|
|
Result string
|
|
|
|
}
|
|
|
|
|
|
|
|
// StringManipulation is an interface that holds all abstract methods to manipulate strings
|
|
|
|
type StringManipulation interface {
|
2023-01-20 08:17:29 +03:00
|
|
|
Acronym() StringManipulation
|
2020-04-05 12:11:56 +03:00
|
|
|
Between(start, end string) StringManipulation
|
|
|
|
Boolean() bool
|
|
|
|
CamelCase(rule ...string) string
|
|
|
|
ContainsAll(check ...string) bool
|
|
|
|
Delimited(delimiter string, rule ...string) StringManipulation
|
2020-04-07 07:57:58 +03:00
|
|
|
First(length int) string
|
2020-04-05 12:11:56 +03:00
|
|
|
Get() string
|
|
|
|
KebabCase(rule ...string) StringManipulation
|
2020-04-07 07:57:58 +03:00
|
|
|
Last(length int) string
|
2020-04-05 12:11:56 +03:00
|
|
|
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
|
|
|
|
ToLower() string
|
|
|
|
ToUpper() string
|
|
|
|
UcFirst() string
|
2021-05-14 13:41:41 +03:00
|
|
|
Prefix(with string) string
|
|
|
|
Suffix(with string) string
|
2020-04-05 12:11:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// New func returns pointer to input struct
|
|
|
|
func New(val string) StringManipulation {
|
|
|
|
return &input{Input: val}
|
|
|
|
}
|
|
|
|
|
2023-01-20 08:17:29 +03:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) Between(start, end string) StringManipulation {
|
2020-04-22 14:51:08 +03:00
|
|
|
if (start == "" && end == "") || i.Input == "" {
|
2020-04-05 12:11:56 +03:00
|
|
|
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)
|
|
|
|
}
|
2020-04-05 14:02:47 +03:00
|
|
|
i.Result = strings.TrimSpace(i.Input[startIndex:endIndex])
|
2020-04-05 12:11:56 +03:00
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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
|
2020-04-05 12:11:56 +03:00
|
|
|
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
|
|
|
|
}
|
2020-04-07 07:57:58 +03:00
|
|
|
panic(errors.New(InvalidLogicalString))
|
2020-04-05 12:11:56 +03:00
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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 dont have to worry about it
|
2020-04-05 12:11:56 +03:00
|
|
|
// Example input: hello user
|
|
|
|
// Result : HelloUser
|
|
|
|
func (i *input) CamelCase(rule ...string) string {
|
|
|
|
input := getInput(*i)
|
|
|
|
// removing excess space
|
2020-04-05 14:02:47 +03:00
|
|
|
wordArray := caseHelper(input, true, rule...)
|
2020-04-05 12:11:56 +03:00
|
|
|
for i, word := range wordArray {
|
|
|
|
wordArray[i] = ucfirst(word)
|
|
|
|
}
|
|
|
|
return strings.Join(wordArray, "")
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// ContainsAll is variadic function which takes slice of strings as param and checks if they are present
|
|
|
|
// in input and returns boolean value accordingly
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) ContainsAll(check ...string) bool {
|
|
|
|
input := getInput(*i)
|
|
|
|
for _, item := range check {
|
|
|
|
if !strings.Contains(input, item) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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.
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) Delimited(delimiter string, rule ...string) StringManipulation {
|
|
|
|
input := getInput(*i)
|
|
|
|
if strings.TrimSpace(delimiter) == "" {
|
|
|
|
delimiter = "."
|
|
|
|
}
|
2020-04-05 14:02:47 +03:00
|
|
|
wordArray := caseHelper(input, false, rule...)
|
2020-04-05 12:11:56 +03:00
|
|
|
i.Result = strings.Join(wordArray, delimiter)
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
2020-04-07 07:57:58 +03:00
|
|
|
// 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]
|
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// Get simply returns result and can be chained on function which
|
|
|
|
// returns StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) Get() string {
|
|
|
|
return getInput(*i)
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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.
|
2020-04-05 14:02:47 +03:00
|
|
|
// Example input: hello user
|
|
|
|
// Result : hello-user
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) KebabCase(rule ...string) StringManipulation {
|
|
|
|
input := getInput(*i)
|
2020-04-05 14:02:47 +03:00
|
|
|
wordArray := caseHelper(input, false, rule...)
|
2020-04-05 12:11:56 +03:00
|
|
|
i.Result = strings.Join(wordArray, "-")
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
2020-04-07 07:57:58 +03:00
|
|
|
// 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]
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// LcFirst simply returns result by lower casing first letter of string and it can be chained on
|
|
|
|
// function which return StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) LcFirst() string {
|
|
|
|
input := getInput(*i)
|
2021-11-06 07:59:33 +03:00
|
|
|
for _, v := range input {
|
|
|
|
return string(unicode.ToLower(v)) + input[len(string(v)):]
|
2020-04-05 12:11:56 +03:00
|
|
|
}
|
2021-11-06 07:59:33 +03:00
|
|
|
return ""
|
2020-04-05 12:11:56 +03:00
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// Lines returns slice of strings by removing white space characters
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) Lines() []string {
|
|
|
|
input := getInput(*i)
|
|
|
|
matchWord := regexp.MustCompile(`[\s]*[\W]\pN`)
|
|
|
|
result := matchWord.ReplaceAllString(input, " ")
|
|
|
|
return strings.Fields(strings.TrimSpace(result))
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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
|
2020-04-05 12:11:56 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// RemoveSpecialCharacter removes all special characters and returns the string
|
|
|
|
// it can be chained on function which return StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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.
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) ReplaceFirst(search, replace string) string {
|
|
|
|
input := getInput(*i)
|
|
|
|
return replaceStr(input, search, replace, First)
|
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// 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
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) ReplaceLast(search, replace string) string {
|
|
|
|
input := getInput(*i)
|
|
|
|
return replaceStr(input, search, replace, Last)
|
|
|
|
}
|
2020-04-05 14:02:47 +03:00
|
|
|
|
|
|
|
// Reverse reverses the passed strings
|
|
|
|
// it can be chained on function which return StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// Shuffle shuffles the given string randomly
|
|
|
|
// it can be chained on function which return StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// 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.
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) SnakeCase(rule ...string) StringManipulation {
|
|
|
|
input := getInput(*i)
|
2020-04-05 14:02:47 +03:00
|
|
|
wordArray := caseHelper(input, false, rule...)
|
2020-04-05 12:11:56 +03:00
|
|
|
i.Result = strings.Join(wordArray, "_")
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// Surround takes one param with which is used to surround user input and it
|
|
|
|
// can be chained on function which return StringManipulation interface.
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) Surround(with string) string {
|
|
|
|
input := getInput(*i)
|
|
|
|
return with + input + with
|
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// 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
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) Tease(length int, indicator string) string {
|
|
|
|
input := getInput(*i)
|
|
|
|
if input == "" || len(input) < length {
|
|
|
|
return input
|
|
|
|
}
|
|
|
|
return input[:length] + indicator
|
|
|
|
}
|
|
|
|
|
2020-04-05 15:57:30 +03:00
|
|
|
// ToLower makes all string of user input to lowercase
|
2020-04-05 14:02:47 +03:00
|
|
|
// it can be chained on function which return StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) ToLower() (result string) {
|
|
|
|
input := getInput(*i)
|
|
|
|
return strings.ToLower(input)
|
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// ToUpper makes all string of user input to uppercase
|
|
|
|
// it can be chained on function which return StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) ToUpper() string {
|
|
|
|
input := getInput(*i)
|
|
|
|
return strings.ToUpper(input)
|
|
|
|
}
|
|
|
|
|
2020-04-05 14:02:47 +03:00
|
|
|
// UcFirst makes first word of user input to uppercase
|
|
|
|
// it can be chained on function which return StringManipulation interface
|
2020-04-05 12:11:56 +03:00
|
|
|
func (i *input) UcFirst() string {
|
|
|
|
input := getInput(*i)
|
|
|
|
return ucfirst(input)
|
|
|
|
}
|
2021-05-14 13:41:41 +03:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|