forked from gSpera/morse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmorse.go
172 lines (139 loc) · 4.94 KB
/
morse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package mltmorse
import (
"io"
"strings"
"unicode"
)
// ErrorHandler is a function used by Converter when it encounters an unknown character
// Returns the text to insert at the place of the unknown character
// This may not(but can if necessary) corrupt the output inserting invalid morse character
type ErrorHandler func(error) string
// StrNormalizer is a function used by Converter when it normalizes a string
type StrNormalizer func(string) []rune
// Converter is a Morse from/to Text converter, it handles the conversion and error handling
type Converter struct {
runeToMorse map[rune]string
morseToRune map[string]rune
charSeparator string
wordSeparator string
convertToUpper bool
trailingSeparator bool
Normalizer StrNormalizer
Handling ErrorHandler
}
// NewConverter creates a new converter with the specified configuration
// convertingMap is an EncodingMap, it contains how the characters will be translated, usually this is set to DefaultMorse
// but a custom one can be used. A nil convertingMap will panic.
func NewConverter(convertingMap EncodingMap, options ...ConverterOption) Converter {
if convertingMap == nil {
panic("Using a nil EncodingMap")
}
morseToRune := reverseEncodingMap(convertingMap)
c := Converter{
runeToMorse: convertingMap,
morseToRune: morseToRune,
charSeparator: " ",
wordSeparator: "",
convertToUpper: false,
trailingSeparator: false,
Normalizer: NormStr,
Handling: IgnoreHandler,
}
for _, opt := range options {
c = opt(c)
}
//Set wordSeparator as default
if c.wordSeparator == "" {
//Use custom space if avaible
sp, ok := c.runeToMorse[' ']
if !ok {
//Fallback to the default Space
sp = Space
}
c.wordSeparator = c.charSeparator + sp + c.charSeparator
}
return c
}
// ToText converts a morse string to his textual representation
//
// For Example: "- . ... -" -> "TEST"
func (c Converter) ToText(morse string) string {
out := make([]rune, 0, int(float64(len(morse))/averageSize))
words := strings.Split(morse, c.charSeparator+Space+c.charSeparator)
for _, word := range words {
chars := strings.Split(word, c.charSeparator)
for _, ch := range chars {
text, ok := c.morseToRune[ch]
if !ok {
hand := []rune(c.Handling(ErrNoEncoding{string(ch)}))
out = append(out, hand...)
//Add a charSeparator is the len of the result is not zero
if len(hand) != 0 {
out = append(out, []rune(c.charSeparator)...)
}
continue
}
out = append(out, text)
}
out = append(out, ' ')
}
//Remove last charSeparator
if !c.trailingSeparator && len(out) >= len(c.charSeparator) {
out = out[:len(out)-len(c.charSeparator)]
}
return string(out)
}
// ToMorse converts a text to his morse representation
// Lowercase characters are automatically converted to Uppercase
//
// For Example: "Test" -> "- . ... -"
func (c Converter) ToMorse(text string) string {
out := make([]rune, 0, int(float64(len([]rune(text)))*averageSize))
/*
TODO 言語特有の処理が必要な場合について
言語ごとに設定などを作って、引数に応じて処理を変えるというようにして、コードの可読性をあげる
ただし変換に関してオプションを用意できてない
*/
normalized := c.Normalizer(text)
for _, ch := range normalized {
// 大文字に変換するフラグをなくして、normalizer の機能として組み込む仕様にするかどうか
if c.convertToUpper {
ch = unicode.ToUpper(ch)
}
if _, ok := c.runeToMorse[ch]; !ok {
hand := []rune(c.Handling(ErrNoEncoding{string(ch)}))
out = append(out, hand...)
//Add a charSeparator is the len of the result is not zero
if len(hand) != 0 {
out = append(out, []rune(c.charSeparator)...)
}
continue
}
out = append(out, []rune(c.runeToMorse[ch])...)
out = append(out, []rune(c.charSeparator)...)
}
//Remove last charSeparator
if !c.trailingSeparator && len(out) >= len(c.charSeparator) {
out = out[:len(out)-len(c.charSeparator)]
}
return string(out)
}
// ToMorseWriter translate all the text written to the returned io.Writer in morse code and writes it in the input io.Writer
func (c Converter) ToMorseWriter(output io.Writer) io.Writer {
return translateToMorse{conv: c, buffer: make([]byte, 10), output: output}
}
// ToTextWriter translate all the text written to the returned io.Writer from morse code and writes it in the input io.Writer
func (c Converter) ToTextWriter(output io.Writer) io.Writer {
return translateToText{conv: c, buffer: make([]byte, 10), output: output}
}
// CharSeparator returns the charSeparator of the converter
func (c Converter) CharSeparator() string { return c.charSeparator }
// EncodingMap returns a copy of the EncodingMap inside the Converter,
// modifying the returned map will not change the internal one
func (c Converter) EncodingMap() EncodingMap {
ret := make(EncodingMap, len(c.runeToMorse))
for k, v := range c.runeToMorse {
ret[k] = v
}
return ret
}