diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13e75bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# IDE +.idea +*.iml + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/config/definitions.go b/config/definitions.go new file mode 100644 index 0000000..81cef0f --- /dev/null +++ b/config/definitions.go @@ -0,0 +1,45 @@ +package config + +import ( + "gopkg.in/yaml.v2" + "io/ioutil" + "log" + "strings" +) + +const DefinitionDir = "./definitions/" +const DefinitionFileExt = "yaml" + +func LoadDefinitions() map[string][]string { + fileList, err := ioutil.ReadDir(DefinitionDir) + if err != nil { + log.Fatalf("Could not list the definition folder: %v", err) + } + + definitionMap := make(map[string][]string) + + for _, file := range fileList { + fileName := file.Name() + + extension := fileName[strings.IndexByte(fileName, '.')+1:] + if extension == DefinitionFileExt { + fileContent, err := ioutil.ReadFile(DefinitionDir + fileName) + if err != nil { + log.Fatalf("Could not read a definition file: %v", err) + } + + fileDefinitionChunk := make(map[string][]string) + err = yaml.Unmarshal(fileContent, &fileDefinitionChunk) + if err != nil { + log.Fatalf("Could not parse a definition file: %v", err) + } + + for definitionKey, definitionValues := range fileDefinitionChunk { + // TODO - deduplication + definitionMap[definitionKey] = append(definitionMap[definitionKey], definitionValues...) + } + } + } + + return definitionMap +} diff --git a/definitions/_global.yaml b/definitions/_global.yaml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/definitions/_global.yaml @@ -0,0 +1 @@ + diff --git a/definitions/cs_CZ.yaml b/definitions/cs_CZ.yaml new file mode 100644 index 0000000..b2908d1 --- /dev/null +++ b/definitions/cs_CZ.yaml @@ -0,0 +1,7 @@ +after: + - a + - s + - z + - za + - po + - do diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c25c45a --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module nbspify + +require gopkg.in/yaml.v2 v2.2.2 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bd555a3 --- /dev/null +++ b/go.sum @@ -0,0 +1,3 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/input/reader.go b/input/reader.go new file mode 100644 index 0000000..bcc58b9 --- /dev/null +++ b/input/reader.go @@ -0,0 +1,36 @@ +package input + +import ( + "bufio" + "io" + "log" + "os" +) + +func ReadInput() string { + fileInfo, err := os.Stdin.Stat() + if err != nil { + panic(err) + } + + if fileInfo.Mode()&os.ModeCharDevice != 0 { + log.Fatal("No input data, exiting...") + } + + reader := bufio.NewReader(os.Stdin) + + var inputRead []rune + for { + input, _, err := reader.ReadRune() + if err != nil && err == io.EOF { + break + } + inputRead = append(inputRead, input) + } + + if len(inputRead) < 0 { + log.Fatal("No input data, exiting...") + } + + return string(inputRead) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..3dbcebc --- /dev/null +++ b/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "log" + "nbspify/config" + "nbspify/input" + nbsperDefinitions "nbspify/nbspers" +) + +func main() { + programInput := input.ReadInput() + if len(programInput) == 0 { + log.Fatalf("The input is empty.") + } + + processedText := programInput + + definitions := config.LoadDefinitions() + + nbspers := getNbspers() + + if nbspers != nil { + for _, nbsper := range nbspers { + definition := definitions[nbsper.GetCode()] + + if len(definition) > 0 { + processedText = nbsper.Apply(processedText, definition) + } + } + } + + // STDOUT + fmt.Print(processedText) +} + +func getNbspers() []nbsperDefinitions.Nbsper { + nbspers := make([]nbsperDefinitions.Nbsper, 0) + + // The order matters as the output is modified in-place... + nbspers = append(nbspers,  erDefinitions.NbsperAround{}) + nbspers = append(nbspers,  erDefinitions.NbsperBefore{}) + nbspers = append(nbspers,  erDefinitions.NbsperAfter{}) + + return nbspers +} diff --git a/nbspers/nbsper.go b/nbspers/nbsper.go new file mode 100644 index 0000000..a3d45a0 --- /dev/null +++ b/nbspers/nbsper.go @@ -0,0 +1,6 @@ +package nbspers + +type Nbsper interface { + GetCode() string + Apply(input string, matchSegments []string) string +} diff --git a/nbspers/nbsper_after.go b/nbspers/nbsper_after.go new file mode 100644 index 0000000..4a4fc26 --- /dev/null +++ b/nbspers/nbsper_after.go @@ -0,0 +1,21 @@ +package nbspers + +import ( + "fmt" + "regexp" + "strings" +) + +type NbsperAfter struct { +} + +func (nbsperAfter *NbsperAfter) GetCode() string { + return "after" +} + +func (nbsperAfter *NbsperAfter) Apply(input string, matchSegments []string) string { + words := strings.Join(matchSegments, "|") + expression := regexp.MustCompile(fmt.Sprintf("(%s) ", words)) + + return expression.ReplaceAllString(input, "$1 ") +} diff --git a/nbspers/nbsper_around.go b/nbspers/nbsper_around.go new file mode 100644 index 0000000..23c1f28 --- /dev/null +++ b/nbspers/nbsper_around.go @@ -0,0 +1,21 @@ +package nbspers + +import ( + "fmt" + "regexp" + "strings" +) + +type NbsperAround struct { +} + +func (nbsperAround *NbsperAround) GetCode() string { + return "around" +} + +func (nbsperAround *NbsperAround) Apply(input string, matchSegments []string) string { + words := strings.Join(matchSegments, "|") + expression := regexp.MustCompile(fmt.Sprintf(" (%s) ", words)) + + return expression.ReplaceAllString(input, " $1 ") +} diff --git a/nbspers/nbsper_before.go b/nbspers/nbsper_before.go new file mode 100644 index 0000000..50dd02e --- /dev/null +++ b/nbspers/nbsper_before.go @@ -0,0 +1,21 @@ +package nbspers + +import ( + "fmt" + "regexp" + "strings" +) + +type NbsperBefore struct { +} + +func (nbsperBefore *NbsperBefore) GetCode() string { + return "before" +} + +func (nbsperBefore *NbsperBefore) Apply(input string, matchSegments []string) string { + words := strings.Join(matchSegments, "|") + expression := regexp.MustCompile(fmt.Sprintf(" (%s)", words)) + + return expression.ReplaceAllString(input, " $1") +}