Skip to content

Commit

Permalink
Create processing/text package (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
sunshineplan committed May 10, 2024
1 parent 85ef473 commit f672d23
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 0 deletions.
64 changes: 64 additions & 0 deletions processing/text/processor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package text

import (
"regexp"
"strings"
)

type Processor interface {
Once() bool
Process(string) (string, error)
}

var (
_ Processor = processor{}
_ Processor = RemoveByRegexp{}
_ Processor = Cut{}
_ Processor = Trim{}
)

type processor struct {
once bool
fn func(string) (string, error)
}

func NewProcessor(once bool, fn func(string) (string, error)) Processor {
return processor{once, fn}
}

func WrapFunc(fn func(string) string) func(string) (string, error) {
return func(s string) (string, error) { return fn(s), nil }
}

func (p processor) Once() bool { return p.once }
func (p processor) Process(s string) (string, error) {
return p.fn(s)
}

type RemoveByRegexp struct {
*regexp.Regexp
}

func (RemoveByRegexp) Once() bool { return false }
func (p RemoveByRegexp) Process(s string) (string, error) {
return p.ReplaceAllString(s, ""), nil
}

type Cut struct {
Sep string
}

func (Cut) Once() bool { return true }
func (p Cut) Process(s string) (string, error) {
before, _, _ := strings.Cut(s, p.Sep)
return before, nil
}

type Trim struct {
Cutset string
}

func (Trim) Once() bool { return false }
func (p Trim) Process(s string) (string, error) {
return strings.Trim(s, p.Cutset), nil
}
62 changes: 62 additions & 0 deletions processing/text/processor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package text

import (
"regexp"
"testing"
)

func TestRemoveByRegexp(t *testing.T) {
for i, testcase := range []struct {
re *regexp.Regexp
s string
expected string
}{
{regexp.MustCompile(""), "", ""},
{regexp.MustCompile(`\d+`), "abc123", "abc"},
{regexp.MustCompile(`\d+$`), "123abc456", "123abc"},
} {
if res, err := NewTasks().Append(RemoveByRegexp{testcase.re}).Process(testcase.s); err != nil {
t.Error(err)
} else if res != testcase.expected {
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
}
}
}

func TestCut(t *testing.T) {
for i, testcase := range []struct {
seq string
s string
expected string
}{
{"", "", ""},
{" ", "abc 123", "abc"},
{" ", " abc 123", ""},
{"abc", "123abc456", "123"},
} {
if res, err := NewTasks().Append(Cut{testcase.seq}).Process(testcase.s); err != nil {
t.Error(err)
} else if res != testcase.expected {
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
}
}
}

func TestTrim(t *testing.T) {
for i, testcase := range []struct {
cutset string
s string
expected string
}{
{"", "", ""},
{" ", " abc 123 ", "abc 123"},
{" ", " abc 123\n", "abc 123\n"},
{" \n", " abc 123\n", "abc 123"},
} {
if res, err := NewTasks().Append(Trim{testcase.cutset}).Process(testcase.s); err != nil {
t.Error(err)
} else if res != testcase.expected {
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
}
}
}
73 changes: 73 additions & 0 deletions processing/text/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package text

import (
"regexp"
"strings"
)

type Tasks struct {
tasks []Processor
}

func NewTasks(tasks ...Processor) *Tasks {
return &Tasks{tasks}
}

func (t *Tasks) Process(s string) (string, error) {
var err error
for first, output := true, s; ; {
for _, task := range t.tasks {
if first || !task.Once() {
s, err = task.Process(s)
if err != nil {
return "", err
}
}
}
if s == output {
return output, nil
} else {
output = s
}
if first {
first = false
}
}
}

func (t *Tasks) ProcessAll(s []string) ([]string, error) {
var output []string
for _, i := range s {
s, err := t.Process(i)
if err != nil {
return nil, err
}
output = append(output, s)
}
return output, nil
}

func (t *Tasks) Append(tasks ...Processor) *Tasks {
t.tasks = append(t.tasks, tasks...)
return t
}

func (t *Tasks) TrimSpace() *Tasks {
return t.Append(NewProcessor(false, WrapFunc(strings.TrimSpace)))
}

func (t *Tasks) CutSpace() *Tasks {
return t.Append(NewProcessor(true, func(s string) (string, error) {
if fs := strings.Fields(s); len(fs) > 0 {
return fs[0], nil
}
return "", nil
}))
}

func (t *Tasks) RemoveParentheses() *Tasks {
return t.Append(
RemoveByRegexp{regexp.MustCompile(`\([^)]*\)`)},
RemoveByRegexp{regexp.MustCompile(`([^)]*)`)},
)
}
81 changes: 81 additions & 0 deletions processing/text/task_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package text

import "testing"

func TestTrimSpace(t *testing.T) {
task := NewTasks().TrimSpace()
for i, testcase := range []struct {
s string
expected string
}{
{"", ""},
{" abc", "abc"},
{"abc\n", "abc"},
{"a b c", "a b c"},
} {
if res, err := task.Process(testcase.s); err != nil {
t.Error(err)
} else if res != testcase.expected {
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
}
}
}

func TestCutSpace(t *testing.T) {
task := NewTasks().CutSpace()
for i, testcase := range []struct {
s string
expected string
}{
{"", ""},
{" abc", "abc"},
{"abc def", "abc"},
{"abc\ndef", "abc"},
} {
if res, err := task.Process(testcase.s); err != nil {
t.Error(err)
} else if res != testcase.expected {
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
}
}
}

func TestRemoveParentheses(t *testing.T) {
task := NewTasks().RemoveParentheses()
for i, testcase := range []struct {
s string
expected string
}{
{"", ""},
{"abc", "abc"},
{"abc(123)", "abc"},
{"abc(123)", "abc"},
{"abc(123)", "abc(123)"},
{"abc(123)def", "abcdef"},
} {
if res, err := task.Process(testcase.s); err != nil {
t.Error(err)
} else if res != testcase.expected {
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
}
}
}

func TestTasks(t *testing.T) {
task := NewTasks().TrimSpace().RemoveParentheses().CutSpace()
for i, testcase := range []struct {
s string
expected string
}{
{"", ""},
{" abc(123)\n", "abc"},
{"abc (123)", "abc"},
{"(123)abc", "abc"},
} {
if res, err := task.Process(testcase.s); err != nil {
t.Error(err)
} else if res != testcase.expected {
t.Errorf("#%d: got %q; want %q", i, res, testcase.expected)
}
}
}

0 comments on commit f672d23

Please sign in to comment.