Skip to content

Commit f672d23

Browse files
authored
Create processing/text package (#44)
1 parent 85ef473 commit f672d23

File tree

4 files changed

+280
-0
lines changed

4 files changed

+280
-0
lines changed

processing/text/processor.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package text
2+
3+
import (
4+
"regexp"
5+
"strings"
6+
)
7+
8+
type Processor interface {
9+
Once() bool
10+
Process(string) (string, error)
11+
}
12+
13+
var (
14+
_ Processor = processor{}
15+
_ Processor = RemoveByRegexp{}
16+
_ Processor = Cut{}
17+
_ Processor = Trim{}
18+
)
19+
20+
type processor struct {
21+
once bool
22+
fn func(string) (string, error)
23+
}
24+
25+
func NewProcessor(once bool, fn func(string) (string, error)) Processor {
26+
return processor{once, fn}
27+
}
28+
29+
func WrapFunc(fn func(string) string) func(string) (string, error) {
30+
return func(s string) (string, error) { return fn(s), nil }
31+
}
32+
33+
func (p processor) Once() bool { return p.once }
34+
func (p processor) Process(s string) (string, error) {
35+
return p.fn(s)
36+
}
37+
38+
type RemoveByRegexp struct {
39+
*regexp.Regexp
40+
}
41+
42+
func (RemoveByRegexp) Once() bool { return false }
43+
func (p RemoveByRegexp) Process(s string) (string, error) {
44+
return p.ReplaceAllString(s, ""), nil
45+
}
46+
47+
type Cut struct {
48+
Sep string
49+
}
50+
51+
func (Cut) Once() bool { return true }
52+
func (p Cut) Process(s string) (string, error) {
53+
before, _, _ := strings.Cut(s, p.Sep)
54+
return before, nil
55+
}
56+
57+
type Trim struct {
58+
Cutset string
59+
}
60+
61+
func (Trim) Once() bool { return false }
62+
func (p Trim) Process(s string) (string, error) {
63+
return strings.Trim(s, p.Cutset), nil
64+
}

processing/text/processor_test.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package text
2+
3+
import (
4+
"regexp"
5+
"testing"
6+
)
7+
8+
func TestRemoveByRegexp(t *testing.T) {
9+
for i, testcase := range []struct {
10+
re *regexp.Regexp
11+
s string
12+
expected string
13+
}{
14+
{regexp.MustCompile(""), "", ""},
15+
{regexp.MustCompile(`\d+`), "abc123", "abc"},
16+
{regexp.MustCompile(`\d+$`), "123abc456", "123abc"},
17+
} {
18+
if res, err := NewTasks().Append(RemoveByRegexp{testcase.re}).Process(testcase.s); err != nil {
19+
t.Error(err)
20+
} else if res != testcase.expected {
21+
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
22+
}
23+
}
24+
}
25+
26+
func TestCut(t *testing.T) {
27+
for i, testcase := range []struct {
28+
seq string
29+
s string
30+
expected string
31+
}{
32+
{"", "", ""},
33+
{" ", "abc 123", "abc"},
34+
{" ", " abc 123", ""},
35+
{"abc", "123abc456", "123"},
36+
} {
37+
if res, err := NewTasks().Append(Cut{testcase.seq}).Process(testcase.s); err != nil {
38+
t.Error(err)
39+
} else if res != testcase.expected {
40+
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
41+
}
42+
}
43+
}
44+
45+
func TestTrim(t *testing.T) {
46+
for i, testcase := range []struct {
47+
cutset string
48+
s string
49+
expected string
50+
}{
51+
{"", "", ""},
52+
{" ", " abc 123 ", "abc 123"},
53+
{" ", " abc 123\n", "abc 123\n"},
54+
{" \n", " abc 123\n", "abc 123"},
55+
} {
56+
if res, err := NewTasks().Append(Trim{testcase.cutset}).Process(testcase.s); err != nil {
57+
t.Error(err)
58+
} else if res != testcase.expected {
59+
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
60+
}
61+
}
62+
}

processing/text/task.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package text
2+
3+
import (
4+
"regexp"
5+
"strings"
6+
)
7+
8+
type Tasks struct {
9+
tasks []Processor
10+
}
11+
12+
func NewTasks(tasks ...Processor) *Tasks {
13+
return &Tasks{tasks}
14+
}
15+
16+
func (t *Tasks) Process(s string) (string, error) {
17+
var err error
18+
for first, output := true, s; ; {
19+
for _, task := range t.tasks {
20+
if first || !task.Once() {
21+
s, err = task.Process(s)
22+
if err != nil {
23+
return "", err
24+
}
25+
}
26+
}
27+
if s == output {
28+
return output, nil
29+
} else {
30+
output = s
31+
}
32+
if first {
33+
first = false
34+
}
35+
}
36+
}
37+
38+
func (t *Tasks) ProcessAll(s []string) ([]string, error) {
39+
var output []string
40+
for _, i := range s {
41+
s, err := t.Process(i)
42+
if err != nil {
43+
return nil, err
44+
}
45+
output = append(output, s)
46+
}
47+
return output, nil
48+
}
49+
50+
func (t *Tasks) Append(tasks ...Processor) *Tasks {
51+
t.tasks = append(t.tasks, tasks...)
52+
return t
53+
}
54+
55+
func (t *Tasks) TrimSpace() *Tasks {
56+
return t.Append(NewProcessor(false, WrapFunc(strings.TrimSpace)))
57+
}
58+
59+
func (t *Tasks) CutSpace() *Tasks {
60+
return t.Append(NewProcessor(true, func(s string) (string, error) {
61+
if fs := strings.Fields(s); len(fs) > 0 {
62+
return fs[0], nil
63+
}
64+
return "", nil
65+
}))
66+
}
67+
68+
func (t *Tasks) RemoveParentheses() *Tasks {
69+
return t.Append(
70+
RemoveByRegexp{regexp.MustCompile(`\([^)]*\)`)},
71+
RemoveByRegexp{regexp.MustCompile(`([^)]*)`)},
72+
)
73+
}

processing/text/task_test.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package text
2+
3+
import "testing"
4+
5+
func TestTrimSpace(t *testing.T) {
6+
task := NewTasks().TrimSpace()
7+
for i, testcase := range []struct {
8+
s string
9+
expected string
10+
}{
11+
{"", ""},
12+
{" abc", "abc"},
13+
{"abc\n", "abc"},
14+
{"a b c", "a b c"},
15+
} {
16+
if res, err := task.Process(testcase.s); err != nil {
17+
t.Error(err)
18+
} else if res != testcase.expected {
19+
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
20+
}
21+
}
22+
}
23+
24+
func TestCutSpace(t *testing.T) {
25+
task := NewTasks().CutSpace()
26+
for i, testcase := range []struct {
27+
s string
28+
expected string
29+
}{
30+
{"", ""},
31+
{" abc", "abc"},
32+
{"abc def", "abc"},
33+
{"abc\ndef", "abc"},
34+
} {
35+
if res, err := task.Process(testcase.s); err != nil {
36+
t.Error(err)
37+
} else if res != testcase.expected {
38+
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
39+
}
40+
}
41+
}
42+
43+
func TestRemoveParentheses(t *testing.T) {
44+
task := NewTasks().RemoveParentheses()
45+
for i, testcase := range []struct {
46+
s string
47+
expected string
48+
}{
49+
{"", ""},
50+
{"abc", "abc"},
51+
{"abc(123)", "abc"},
52+
{"abc(123)", "abc"},
53+
{"abc(123)", "abc(123)"},
54+
{"abc(123)def", "abcdef"},
55+
} {
56+
if res, err := task.Process(testcase.s); err != nil {
57+
t.Error(err)
58+
} else if res != testcase.expected {
59+
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
60+
}
61+
}
62+
}
63+
64+
func TestTasks(t *testing.T) {
65+
task := NewTasks().TrimSpace().RemoveParentheses().CutSpace()
66+
for i, testcase := range []struct {
67+
s string
68+
expected string
69+
}{
70+
{"", ""},
71+
{" abc(123)\n", "abc"},
72+
{"abc (123)", "abc"},
73+
{"(123)abc", "abc"},
74+
} {
75+
if res, err := task.Process(testcase.s); err != nil {
76+
t.Error(err)
77+
} else if res != testcase.expected {
78+
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)