diff --git a/tr/.gitignore b/tr/.gitignore new file mode 100644 index 0000000..ba5489b --- /dev/null +++ b/tr/.gitignore @@ -0,0 +1,2 @@ +tr +tr.exe diff --git a/tr/Makefile b/tr/Makefile new file mode 100644 index 0000000..bea7546 --- /dev/null +++ b/tr/Makefile @@ -0,0 +1,4 @@ + + +build: + go build . diff --git a/tr/go.mod b/tr/go.mod new file mode 100644 index 0000000..1e7d485 --- /dev/null +++ b/tr/go.mod @@ -0,0 +1,3 @@ +module lcthw.dev/go/go-coreutils/tr + +go 1.24.2 diff --git a/tr/main.go b/tr/main.go new file mode 100644 index 0000000..677811e --- /dev/null +++ b/tr/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "flag" + "os" + "bufio" + "strings" + "fmt" + "log" +) + +type Opts struct { + Compliment bool + Delete bool + Squeeze bool + Truncate bool +} + +type Translator struct { + opts Opts + TwoArgs bool + RuneMap map[rune]rune +} + +func (tr *Translator) ParseOpts() { + var from []rune + var to []rune + tr.RuneMap = make(map[rune]rune) + tr.TwoArgs = true + + flag.BoolVar(&tr.opts.Compliment, "c", false, "Use compliment of array1") + flag.BoolVar(&tr.opts.Delete, "d", false, "Delete chars in array1") + flag.BoolVar(&tr.opts.Squeeze, "s", false, "Squeeze chars in array2") + flag.BoolVar(&tr.opts.Truncate, "t", false, "Truncate array1 to array2 length") + flag.Parse() + + args := flag.Args() + + if flag.NArg() == 1 { + from, to = []rune(args[0]), []rune(args[0]) + tr.TwoArgs = false + } else if flag.NArg() == 2 { + from, to = []rune(args[0]), []rune(args[1]) + } else { + log.Fatal("USAGE: tr [-c] [-d] [-s] [-t] [array2]") + } + + for i, ch := range from { + tr.RuneMap[ch] = to[i] + } +} + +func (tr *Translator) Translate(from rune) rune { + if !tr.TwoArgs { log.Fatal("translate requires two args") } + + to, ok := tr.RuneMap[from] + + if ok { + return to + } else { + return from + } +} + +func (tr *Translator) Delete(line string) string { + result := make([]rune, 0, len(line)) + + for _, ch := range []rune(line) { + _, ok := tr.RuneMap[ch] + + if !ok { + result = append(result, ch) + } + } + + return string(result) +} + +func (tr *Translator) Process(line string) { + if tr.opts.Delete { + line = tr.Delete(line) + } else { + line = strings.Map(tr.Translate, line) + } + + fmt.Print(line) +} + +func main() { + tr := new(Translator) + tr.ParseOpts() + + scan := bufio.NewScanner(os.Stdin) + + for scan.Scan() { + line := scan.Text() + "\n" + + tr.Process(line) + } +} diff --git a/wc/go.mod b/wc/go.mod index 664529c..4659f5f 100644 --- a/wc/go.mod +++ b/wc/go.mod @@ -1,3 +1,3 @@ -module MY/wc +module lcthw.dev/go/go-coreutils/wc go 1.24.2