Skip to content
This repository was archived by the owner on Sep 7, 2025. It is now read-only.

Commit 23ba5b6

Browse files
committed
String Helpers from confetti-framework/support#5 PR
1 parent 4a98a3e commit 23ba5b6

File tree

2 files changed

+375
-1
lines changed

2 files changed

+375
-1
lines changed

support/str/str.go

Lines changed: 219 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package str
22

3-
import "unicode"
3+
import (
4+
"regexp"
5+
"strings"
6+
"unicode"
7+
)
48

59
func UpperFirst(input string) string {
610
if len(input) == 0 {
@@ -19,3 +23,217 @@ func InSlice(input interface{}, expects ...interface{}) bool {
1923
}
2024
return false
2125
}
26+
27+
// Return the remainder of a string after the first occurrence of a given value.
28+
func After(subject string, search string) string {
29+
if len(search) == 0 {
30+
return subject
31+
}
32+
results := strings.SplitN(subject, search, 2)
33+
return results[len(results)-1]
34+
}
35+
36+
// Return the remainder of a string after the last occurrence of a given value.
37+
func AfterLast(subject string, search string) string {
38+
if len(search) == 0 {
39+
return subject
40+
}
41+
position := strings.LastIndex(subject, search)
42+
43+
if position == -1 {
44+
return subject
45+
}
46+
47+
return subject[position+len(search):]
48+
}
49+
50+
// Get the portion of a string before the first occurrence of a given value.
51+
func Before(subject string, search string) string {
52+
if len(search) == 0 {
53+
return subject
54+
}
55+
position := strings.Index(subject, search)
56+
57+
if position == -1 {
58+
return subject
59+
}
60+
61+
return subject[:position]
62+
}
63+
64+
func BeforeLast(subject string, search string) string {
65+
if len(search) == 0 {
66+
return subject
67+
}
68+
position := strings.LastIndex(subject, search)
69+
70+
if position == -1 {
71+
return subject
72+
}
73+
74+
return subject[:position]
75+
}
76+
77+
func Between(subject string, from string, to string) string {
78+
if len(from) == 0 || len(to) == 0 {
79+
return subject
80+
}
81+
82+
return BeforeLast(After(subject, from), to)
83+
}
84+
85+
func Contains(haystack string, needle string) bool {
86+
if len(needle) == 0 {
87+
return false
88+
}
89+
90+
return strings.Contains(haystack, needle)
91+
}
92+
93+
func ContainsFromSlice(haystack string, needles []string) bool {
94+
if len(needles) == 0 {
95+
return false
96+
}
97+
98+
for _, needle := range needles {
99+
if Contains(haystack, needle) {
100+
return true
101+
}
102+
}
103+
104+
return false
105+
}
106+
107+
func ContainsAllFromSlice(haystack string, needles []string) bool {
108+
if len(needles) == 0 {
109+
return false
110+
}
111+
112+
for _, needle := range needles {
113+
if !Contains(haystack, needle) {
114+
return false
115+
}
116+
}
117+
118+
return true
119+
}
120+
121+
func EndsWith(haystack string, needle string) bool {
122+
if len(needle) == 0 {
123+
return false
124+
}
125+
126+
return strings.HasSuffix(haystack, needle)
127+
}
128+
129+
func StartsWith(haystack string, needle string) bool {
130+
if len(needle) == 0 {
131+
return false
132+
}
133+
134+
return strings.HasPrefix(haystack, needle)
135+
}
136+
137+
func Lower(value string) string {
138+
return strings.ToLower(value)
139+
}
140+
141+
func Upper(value string) string {
142+
return strings.ToUpper(value)
143+
}
144+
145+
func Finish(value string, cap string) string {
146+
quoted := regexp.QuoteMeta(cap)
147+
148+
re := regexp.MustCompile("(?:" + quoted + ")+$")
149+
return re.ReplaceAllString(value, "") + cap
150+
}
151+
152+
func Start(value string, prefix string) string {
153+
quoted := regexp.QuoteMeta(prefix)
154+
155+
re := regexp.MustCompile("^(?:" + quoted + ")+")
156+
return prefix + re.ReplaceAllString(value, "")
157+
}
158+
159+
//
160+
//func Title(value string) string {
161+
// // TODO
162+
// return ""
163+
//}
164+
//
165+
// func Kebab(vale string) string {
166+
// // TODO
167+
// return ""
168+
// }
169+
//
170+
// func Length(value string) int {
171+
// // TODO
172+
// return 0
173+
// }
174+
//
175+
// func LimitCharacters(value string, limit int, end string) string{
176+
// // TODO
177+
// return ""
178+
// }
179+
//
180+
// func LimitWords(value string, limit int, end string) string{
181+
// // TODO
182+
// return ""
183+
// }
184+
//
185+
// func PadBoth(value string, length int, pad string) string {
186+
// // TODO
187+
// return ""
188+
// }
189+
//
190+
// func PadLeft(value string, length int, pad string) string {
191+
// // TODO
192+
// return ""
193+
// }
194+
//
195+
// func PadRight(value string, length int, pad string) string {
196+
// // TODO
197+
// return ""
198+
// }
199+
//
200+
// func ReplaceArray(search string, replace []string, subject string) string {
201+
// // TODO
202+
// return ""
203+
// }
204+
//
205+
// func ReplaceFirst(search string, replace string, subject string) string {
206+
// // TODO
207+
// return ""
208+
// }
209+
//
210+
// func ReplaceLast(search string, replace string, subject string) string {
211+
// // TODO
212+
// return ""
213+
// }
214+
//
215+
// func Slug(value string) string {
216+
// // TODO
217+
// return ""
218+
// }
219+
//
220+
// func SlugWithDelimiter(value string, delimiter string) string {
221+
// // TODO
222+
// return ""
223+
// }
224+
//
225+
// func Snake(value string) string {
226+
// // TODO
227+
// return ""
228+
// }
229+
//
230+
// func Studly(value string) string {
231+
// // TODO
232+
// return ""
233+
// }
234+
//
235+
// func UcFirst(value string) string {
236+
// // TODO
237+
// return ""
238+
// }
239+
//

support/test/str_test.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,159 @@ func Test_in_slice_with_multiple_one_matched_parameters(t *testing.T) {
3535
func Test_in_slice_with_integer(t *testing.T) {
3636
require.True(t, str.InSlice(1, 0, 1))
3737
}
38+
39+
func Test_After(t *testing.T) {
40+
// TODO: What if nothing is found?
41+
require.Equal(t, "", str.After("", ""))
42+
require.Equal(t, "", str.After("", "han"))
43+
require.Equal(t, "hannah", str.After("hannah", ""))
44+
require.Equal(t, "nah", str.After("hannah", "han"))
45+
require.Equal(t, "nah", str.After("hannah", "n"))
46+
require.Equal(t, "nah", str.After("eee hannah", "han"))
47+
require.Equal(t, "nah", str.After("ééé hannah", "han"))
48+
require.Equal(t, "hannah", str.After("hannah", "xxxx"))
49+
require.Equal(t, "nah", str.After("han0nah", "0"))
50+
require.Equal(t, "nah", str.After("han2nah", "2"))
51+
}
52+
53+
func Test_AfterLast(t *testing.T) {
54+
// TODO: What if nothing is found?
55+
require.Equal(t, "", str.After("", ""))
56+
require.Equal(t, "", str.After("", "han"))
57+
require.Equal(t, "hannah", str.After("hannah", ""))
58+
require.Equal(t, "tte", str.AfterLast("yvette", "yve"))
59+
require.Equal(t, "e", str.AfterLast("yvette", "t"))
60+
require.Equal(t, "e", str.AfterLast("ééé yvette", "t"))
61+
require.Equal(t, "", str.AfterLast("yvette", "tte"))
62+
require.Equal(t, "yvette", str.AfterLast("yvette", "xxxx"))
63+
require.Equal(t, "te", str.AfterLast("yv0et0te", "0"))
64+
require.Equal(t, "te", str.AfterLast("yv0et0te", "0"))
65+
require.Equal(t, "te", str.AfterLast("yv2et2te", "2"))
66+
require.Equal(t, "foo", str.AfterLast("----foo", "---"))
67+
}
68+
69+
func Test_Before(t *testing.T) {
70+
require.Equal(t, "hannah", str.Before("hannah", ""))
71+
require.Equal(t, "han", str.Before("hannah", "nah"))
72+
require.Equal(t, "ha", str.Before("hannah", "n"))
73+
require.Equal(t, "ééé ", str.Before("ééé hannah", "han"))
74+
require.Equal(t, "hannah", str.Before("hannah", "xxxx"))
75+
require.Equal(t, "han", str.Before("han0nah", "0"))
76+
require.Equal(t, "han", str.Before("han0nah", "0"))
77+
require.Equal(t, "han", str.Before("han2nah", "2"))
78+
}
79+
80+
func Test_BeforeLast(t *testing.T) {
81+
require.Equal(t, "yve", str.BeforeLast("yvette", "tte"))
82+
require.Equal(t, "yvet", str.BeforeLast("yvette", "t"))
83+
require.Equal(t, "ééé ", str.BeforeLast("ééé yvette", "yve"))
84+
require.Equal(t, "", str.BeforeLast("yvette", "yve"))
85+
require.Equal(t, "yvette", str.BeforeLast("yvette", "xxxx"))
86+
require.Equal(t, "yvette", str.BeforeLast("yvette", ""))
87+
require.Equal(t, "yv0et", str.BeforeLast("yv0et0te", "0"))
88+
require.Equal(t, "yv0et", str.BeforeLast("yv0et0te", "0"))
89+
require.Equal(t, "yv2et", str.BeforeLast("yv2et2te", "2"))
90+
}
91+
92+
func Test_Between(t *testing.T) {
93+
require.Equal(t, "abc", str.Between("abc", "", "c"))
94+
require.Equal(t, "abc", str.Between("abc", "a", ""))
95+
require.Equal(t, "abc", str.Between("abc", "", ""))
96+
require.Equal(t, "b", str.Between("abc", "a", "c"))
97+
require.Equal(t, "b", str.Between("dddabc", "a", "c"))
98+
require.Equal(t, "b", str.Between("abcddd", "a", "c"))
99+
require.Equal(t, "b", str.Between("dddabcddd", "a", "c"))
100+
require.Equal(t, "nn", str.Between("hannah", "ha", "ah"))
101+
require.Equal(t, "a]ab[b", str.Between("[a]ab[b]", "[", "]"))
102+
require.Equal(t, "foo", str.Between("foofoobar", "foo", "bar"))
103+
require.Equal(t, "bar", str.Between("foobarbar", "foo", "bar"))
104+
}
105+
106+
func Test_Contains(t *testing.T) {
107+
require.True(t, str.Contains("taylor", "ylo"))
108+
require.True(t, str.Contains("taylor", "taylor"))
109+
require.False(t, str.Contains("taylor", "xxx"))
110+
require.False(t, str.Contains("taylor", ""))
111+
require.False(t, str.Contains("", ""))
112+
}
113+
114+
func Test_ContainsFromSlice(t *testing.T) {
115+
require.True(t, str.ContainsFromSlice("taylor", []string{"ylo"}))
116+
require.True(t, str.ContainsFromSlice("taylor", []string{"xxx", "ylo"}))
117+
require.False(t, str.ContainsFromSlice("taylor", []string{"xxx"}))
118+
require.False(t, str.ContainsFromSlice("taylor", []string{}))
119+
require.False(t, str.ContainsFromSlice("taylor", []string{""}))
120+
}
121+
122+
func Test_ContainsAllFromSlice(t *testing.T) {
123+
require.True(t, str.ContainsAllFromSlice("This is my name", []string{"This", "is"}))
124+
require.True(t, str.ContainsAllFromSlice("This is my name", []string{"my", "ame"}))
125+
require.True(t, str.ContainsAllFromSlice("taylor", []string{"tay", "ylo"}))
126+
require.False(t, str.ContainsAllFromSlice("taylor", []string{"xxx", "ylo"}))
127+
require.False(t, str.ContainsAllFromSlice("taylor", []string{"xxx", "tay"}))
128+
require.False(t, str.ContainsAllFromSlice("This is my name", []string{"are", "name"}))
129+
require.False(t, str.ContainsAllFromSlice("taylor", []string{}))
130+
require.False(t, str.ContainsAllFromSlice("taylor", []string{"", ""}))
131+
}
132+
133+
func Test_EndsWith(t *testing.T) {
134+
require.True(t, str.EndsWith("This is my name", "name"))
135+
require.True(t, str.EndsWith("This is my name", "e"))
136+
require.True(t, str.EndsWith("jason", "on"))
137+
require.True(t, str.EndsWith("7", "7"))
138+
require.True(t, str.EndsWith("a7", "7"))
139+
require.False(t, str.EndsWith("jason", "no"))
140+
require.False(t, str.EndsWith("jason", ""))
141+
require.False(t, str.EndsWith("", ""))
142+
// Test for multibyte string support
143+
require.True(t, str.EndsWith("Jönköping", "öping"))
144+
require.True(t, str.EndsWith("Malmö", "mö"))
145+
require.True(t, str.EndsWith("Malmö", "mö"))
146+
require.False(t, str.EndsWith("Jönköping", "oping"))
147+
require.False(t, str.EndsWith("Malmö", "mo"))
148+
require.True(t, str.EndsWith("你好", "好"))
149+
require.False(t, str.EndsWith("你好", "你"))
150+
require.False(t, str.EndsWith("你好", "a"))
151+
}
152+
153+
func Test_StartsWith(t *testing.T) {
154+
require.True(t, str.StartsWith("jason", "jas"))
155+
require.True(t, str.StartsWith("jason", "jason"))
156+
require.True(t, str.StartsWith("7a", "7"))
157+
require.True(t, str.StartsWith("7", "7"))
158+
require.False(t, str.StartsWith("jason", "J"))
159+
require.False(t, str.StartsWith("jason", ""))
160+
require.False(t, str.StartsWith("", ""))
161+
// Test for multibyte string support
162+
require.True(t, str.StartsWith("Jönköping", "Jö"))
163+
require.True(t, str.StartsWith("Malmö", "Malmö"))
164+
require.True(t, str.StartsWith("你好", "你"))
165+
require.False(t, str.StartsWith("Jönköping", "Jonko"))
166+
require.False(t, str.StartsWith("Malmö", "Malmo"))
167+
require.False(t, str.StartsWith("你好", "好"))
168+
require.False(t, str.StartsWith("你好", "a"))
169+
}
170+
171+
func Test_Lower(t *testing.T) {
172+
require.Equal(t, "foo bar baz", str.Lower("FOO BAR BAZ"))
173+
require.Equal(t, "foo bar baz", str.Lower("fOo Bar bAz"))
174+
}
175+
176+
func Test_Upper(t *testing.T) {
177+
require.Equal(t, "FOO BAR BAZ", str.Upper("foo bar baz"))
178+
require.Equal(t, "FOO BAR BAZ", str.Upper("fOo Bar bAZ"))
179+
}
180+
181+
func Test_Finish(t *testing.T) {
182+
require.Equal(t, "abbc", str.Finish("ab", "bc"))
183+
require.Equal(t, "abbc", str.Finish("abbcbc", "bc"))
184+
require.Equal(t, "abcbbc", str.Finish("abcbbcbc", "bc"))
185+
require.Equal(t, "this/string/", str.Finish("this/string", "/"))
186+
require.Equal(t, "this/string/", str.Finish("this/string/", "/"))
187+
}
188+
189+
func Test_Start(t *testing.T) {
190+
require.Equal(t, "/test/string", str.Start("test/string", "/"))
191+
require.Equal(t, "/test/string", str.Start("/test/string", "/"))
192+
require.Equal(t, "/test/string", str.Start("//test/string", "/"))
193+
}

0 commit comments

Comments
 (0)