Skip to content

Commit b4ebbf8

Browse files
author
Evan Marcey
committed
Decomposed cleanup. Implementing StringFiltering by Rune func
1 parent a22a8c7 commit b4ebbf8

File tree

4 files changed

+219
-27
lines changed

4 files changed

+219
-27
lines changed

string_filters.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package gostringconverters
2+
3+
import (
4+
"strings"
5+
"unicode"
6+
)
7+
8+
// FilterStringChars - given a string, removes all characters meeting filter conditions
9+
func FilterStringChars(s string, filters []RuneFilterFunc) string {
10+
var result strings.Builder
11+
for _, r := range s {
12+
if !runeIsFiltered(r, filters) {
13+
result.WriteRune(r)
14+
}
15+
}
16+
return result.String()
17+
}
18+
19+
func runeIsFiltered(r rune, filters []RuneFilterFunc) bool {
20+
for _, filter := range filters {
21+
if filter(r) {
22+
return true
23+
}
24+
}
25+
return false
26+
}
27+
28+
// RuneFilterFunc - function that accepts a rune and returns a true if the rune meets a given condition
29+
type RuneFilterFunc func(rune) bool
30+
31+
// ControlCharFilterFunc - checks if rune is a control character
32+
func ControlCharFilterFunc() RuneFilterFunc {
33+
return func(r rune) bool {
34+
return unicode.IsControl(r)
35+
}
36+
}
37+
38+
// RemoveControlCharsFromString - wraps FilterStringByRune to remove all control characters from a string
39+
func RemoveControlCharsFromString(s string) string {
40+
return FilterStringChars(s, []RuneFilterFunc{
41+
ControlCharFilterFunc(),
42+
})
43+
}

string_filters_test.go

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package gostringconverters
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func RuneIsA() RuneFilterFunc {
8+
return func(r rune) bool {
9+
return r == 'a'
10+
}
11+
}
12+
13+
func RuneIsNotA() RuneFilterFunc {
14+
return func(r rune) bool {
15+
return r != 'a'
16+
}
17+
}
18+
19+
func RuneFilterAlwaysTrue() RuneFilterFunc {
20+
return func(r rune) bool {
21+
return true
22+
}
23+
}
24+
25+
func RuneFilterAlwaysFalse() RuneFilterFunc {
26+
return func(r rune) bool {
27+
return false
28+
}
29+
}
30+
31+
func TestRuneIsFiltered(t *testing.T) {
32+
var testCases = []struct {
33+
givenRune rune
34+
givenFilters []RuneFilterFunc
35+
expected bool
36+
}{
37+
{
38+
givenRune: 'a',
39+
givenFilters: []RuneFilterFunc{},
40+
expected: false,
41+
},
42+
{
43+
givenRune: 'a',
44+
givenFilters: []RuneFilterFunc{
45+
RuneIsNotA(),
46+
},
47+
expected: false,
48+
},
49+
{
50+
givenRune: 'a',
51+
givenFilters: []RuneFilterFunc{
52+
RuneIsA(),
53+
},
54+
expected: true,
55+
},
56+
{
57+
givenRune: 'a',
58+
givenFilters: []RuneFilterFunc{
59+
RuneIsNotA(),
60+
RuneFilterAlwaysTrue(),
61+
RuneIsA(),
62+
},
63+
expected: true,
64+
},
65+
{
66+
givenRune: 'a',
67+
givenFilters: []RuneFilterFunc{
68+
RuneIsA(),
69+
RuneIsNotA(),
70+
RuneFilterAlwaysTrue(),
71+
},
72+
expected: true,
73+
},
74+
}
75+
76+
for i, testCase := range testCases {
77+
result := runeIsFiltered(testCase.givenRune, testCase.givenFilters)
78+
if result != testCase.expected {
79+
t.Error("test", i, "given", testCase.givenRune, "and", testCase.givenFilters, "expected", testCase.expected, "result", result)
80+
}
81+
}
82+
}
83+
84+
func TestFilterStringChars(t *testing.T) {
85+
var testCases = []struct {
86+
givenString string
87+
givenFilters []RuneFilterFunc
88+
expected string
89+
}{
90+
{
91+
givenString: "",
92+
givenFilters: []RuneFilterFunc{},
93+
expected: "",
94+
},
95+
{
96+
givenString: "abc",
97+
givenFilters: []RuneFilterFunc{},
98+
expected: "abc",
99+
},
100+
{
101+
givenString: "abc",
102+
givenFilters: []RuneFilterFunc{
103+
RuneFilterAlwaysFalse(),
104+
},
105+
expected: "abc",
106+
},
107+
{
108+
givenString: "abc",
109+
givenFilters: []RuneFilterFunc{
110+
RuneFilterAlwaysTrue(),
111+
},
112+
expected: "",
113+
},
114+
{
115+
givenString: "abc",
116+
givenFilters: []RuneFilterFunc{
117+
RuneIsA(),
118+
},
119+
expected: "bc",
120+
},
121+
{
122+
givenString: "abc",
123+
givenFilters: []RuneFilterFunc{
124+
RuneIsNotA(),
125+
},
126+
expected: "a",
127+
},
128+
{
129+
givenString: "abc",
130+
givenFilters: []RuneFilterFunc{
131+
RuneIsNotA(),
132+
RuneIsA(),
133+
},
134+
expected: "",
135+
},
136+
}
137+
138+
for i, testCase := range testCases {
139+
result := FilterStringChars(testCase.givenString, testCase.givenFilters)
140+
if result != testCase.expected {
141+
t.Error("test", i, "given", testCase.givenString, "and", testCase.givenFilters, "expected", testCase.expected, "result", result)
142+
}
143+
}
144+
}
145+
146+
func TestRemoveControlCharsFromString(t *testing.T) {
147+
var testCases = []struct {
148+
given string
149+
expected string
150+
}{
151+
{
152+
given: "",
153+
expected: "",
154+
},
155+
{
156+
given: "adfadgafdag32412@!@$",
157+
expected: "adfadgafdag32412@!@$",
158+
},
159+
{
160+
given: "adfadgafda" + string(rune(1)) + "g32412@!@$",
161+
expected: "adfadgafdag32412@!@$",
162+
},
163+
{
164+
given: string(rune(1)) + "adfadgafda" + string(rune(1)) + "g32412@!@$" + string(rune(1)),
165+
expected: "adfadgafdag32412@!@$",
166+
},
167+
}
168+
169+
for i, testCase := range testCases {
170+
result := RemoveControlCharsFromString(testCase.given)
171+
if result != testCase.expected {
172+
t.Error("test", i, "given", testCase.given, "expected", testCase.expected, "result", result)
173+
}
174+
}
175+
}

types.go

-5
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,3 @@ type SeparatedCaseOptions struct {
66
Separator rune
77
IsScreaming bool
88
}
9-
10-
type DecomposedRune struct {
11-
NextRunes map[rune]DecomposedRune
12-
Value rune
13-
}

utils.go

+1-22
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func RuneMapToMapFunc(runeMap map[rune]rune, caseSensitive bool) func(rune) rune
5656
}
5757
}
5858

59-
// RuneMapConversion - given a string and a map, converts every rune in string to corresponding map value
59+
// RuneMapToStringConversion - given a string and a map, converts every rune in string to corresponding map value
6060
func RuneMapToStringConversion(s string, m map[rune]string, caseSensitive bool) string {
6161
var output strings.Builder
6262
for _, r := range s {
@@ -77,24 +77,3 @@ func RuneMapToStringConversion(s string, m map[rune]string, caseSensitive bool)
7777
}
7878
return output.String()
7979
}
80-
81-
type RuneFilterFunc func(rune) bool
82-
83-
func FilterStringByRune(s string, filters []RuneFilterFunc) string {
84-
var result strings.Builder
85-
for _, r := range s {
86-
if !runeIsFiltered(r) {
87-
result.WriteRune(r)
88-
}
89-
}
90-
return result.String()
91-
}
92-
93-
func runeIsFiltered(r rune, filters []RuneFilterFunc) bool {
94-
for _, filter := range filters {
95-
if filter(r) {
96-
return true
97-
}
98-
}
99-
return false
100-
}

0 commit comments

Comments
 (0)