-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchar_formatter.go
275 lines (235 loc) · 7.51 KB
/
char_formatter.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
package profaneword
import (
"math/big"
"strings"
"unicode"
)
// NewRandomFormatter is a Returns a RandomlyFormattingCharFormatter that delegates to another CharFormatter at a rate of 50%
func NewRandomFormatter() *RandomlyFormattingCharFormatter {
return &RandomlyFormattingCharFormatter{
thresholdRandom: newFiftyFifty(),
}
}
// RandomlyFormattingCharFormatter is a CharFormatter that delegates randomly to the embedded CharFormatter: Other
type RandomlyFormattingCharFormatter struct {
thresholdRandom
Other CharFormatter
}
func (rff *RandomlyFormattingCharFormatter) SetCharFormatter(wrap CharFormatter) {
rff.Other = wrap
}
func (rff *RandomlyFormattingCharFormatter) GetCharFormatter() CharFormatter {
return rff.Other
}
var _ WrappingCharFormatter = &RandomlyFormattingCharFormatter{}
// FormatRune formats a single rune or not given the Random with threshold
func (rff *RandomlyFormattingCharFormatter) FormatRune(r rune) []rune {
if rff.Rand.Rand().Cmp(rff.Threshold) > 0 {
return rff.Other.FormatRune(r)
}
return []rune{r}
}
// small subset of 1337 alphabet
var l337Map = map[rune][]rune{
'A': {'4'},
'B': {'8'},
'E': {'3'},
'G': {'6'},
'I': {'1'},
'L': {'1'},
'O': {'0'},
'S': {'5'},
'T': {'7'},
'Z': {'2'},
}
// curated list values from https://da.wikipedia.org/wiki/Leetspeak
var uberl337Map = map[rune][][]rune{
'A': {{'4'}, {'/', '\\'}, {'@'}, {'/', '-', '\\'}},
'B': {{'8'}, {'1', '3'}, {'|', '3'}, {'!', '3'}},
'C': {{'['}, {'('}, {'<'}},
'D': {{')'}, {'[', ')'}},
'E': {{'3'}},
'F': {{'|', '='}, {'|', '#'}},
'G': {{'6'}, {'(', '_', '+'}},
'H': {{'#'}, {']', '-', '['}, {'|', '-', '|'}},
'I': {{'1'}, {'!'}, {'|'}},
'J': {{'_', '|'}},
'K': {{'|', '<'}},
'L': {{'1'}, {'|', '_'}, {'|'}},
'M': {{'|', 'v', '|'}, {'|', '\\', '/', '|'}},
'N': {{'|', '\\', '|'}, {'|', 'V'}},
'O': {{'0'}, {'(', ')'}},
'P': {{'|', '>'}},
'Q': {{'(', ')', '_'}},
'R': {{'2'}, {'1', '2'}, {'|', '?'}},
'S': {{'5'}, {'$'}, {'§'}, {'z'}, {'Z'}},
'T': {{'7'}, {'+'}},
'U': {{'(', '_', ')'}, {'|', '_', '|'}},
'V': {{'\\', '/'}},
'W': {{'\\', '/', '\\', '/'}, {'v', 'v'}, {'\'', '/', '/'}, {'\\', '\\', '\''}},
'X': {{'>', '<'}, {'}', '{'}},
'Y': {{'`', '/'}},
'Z': {{'2'}, {'~', '/', '_'}},
}
// L337CharFormatter is a CharFormatter that formats by replacing
// the given rune by a slice if runes as stated in the internal map
type L337CharFormatter struct {
uber1337 map[rune][]rune
}
var _ CharFormatter = L337CharFormatter{}
// FormatRune returns the rune-slice given in the internal map, or returns the input value
func (u L337CharFormatter) FormatRune(r rune) []rune {
rKey := unicode.ToUpper(r)
if leetVal, ok := u.uber1337[rKey]; ok {
return leetVal
}
return []rune{r}
}
// Uber1337Formatter returns an initiated randomly chosen L337CharFormatter with the special uber1337-map
func Uber1337Formatter() Formatter {
uber133Map := buildRandomMap(uberl337Map)
return &CharFormatterDelegatingFormatter{
&L337CharFormatter{
uber133Map,
},
}
}
func buildRandomMap(m map[rune][][]rune) map[rune][]rune {
randDev := CryptoRand{}
var randomMap = make(map[rune][]rune, len(m))
for k, v := range m {
idx := randDev.RandMax(len(v))
randomMap[k] = v[idx]
}
return randomMap
}
// L337Formatter returns a L337CharFormatter with a predefined mapping, the l337map
func L337Formatter() Formatter {
return &CharFormatterDelegatingFormatter{
&L337CharFormatter{
l337Map,
},
}
}
var keyboard = [5]string{
"1234567890-",
"qwertyuiop[",
"asdfghjkl;",
"zxcvbnm,.",
" ",
}
func getNeighbourgChars(r rune) string {
for j, line := range keyboard[1:3] {
jIdx := j + 1
idx := strings.Index(line, string(r))
if idx != -1 {
idxlower := idx - 1
if idxlower == -1 {
idxlower = idx
}
var lower string
if r != 'z' && r != 'x' {
lower = keyboard[jIdx+1][idxlower:idx]
}
return keyboard[jIdx-1][idx:idx+1] + keyboard[jIdx][idxlower:idx+1] + lower
}
}
return string(r)
}
// FatFingerCharFormatter formats the text/rune as if it was types with fat fingers
type FatFingerCharFormatter struct {
RandomDevice
}
var _ CharFormatter = FatFingerCharFormatter{}
// FormatRune returns the slice of runes by finding the neighboring characters (keyboard) and
// returns a random set of characters from within that sequence. it may return the rune itself up to four times
func (ff FatFingerCharFormatter) FormatRune(r rune) []rune {
if ff.Rand().Cmp(big.NewRat(1, 6)) < 0 {
var outRunes []rune
for len(outRunes) == 0 {
if ff.Rand().Cmp(big.NewRat(1, 6)) < 0 {
outRunes = append(outRunes, r)
}
newChars := getNeighbourgChars(r)
if ff.Rand().Cmp(big.NewRat(2, 5)) < 0 {
outRunes = append(outRunes, rune(newChars[ff.RandMax(len(newChars))]))
}
if ff.Rand().Cmp(big.NewRat(1, 12)) < 0 {
outRunes = append(outRunes, rune(newChars[ff.RandMax(len(newChars))]))
}
if ff.Rand().Cmp(big.NewRat(1, 7)) < 0 {
outRunes = append(outRunes, r)
}
}
return outRunes
}
return []rune{r}
}
// NewFatFingerFormatter wraps the FatFingerCharFormatter in a CharFormatterDelegatingFormatter to produce a Formatter
func NewFatFingerFormatter() Formatter {
return &CharFormatterDelegatingFormatter{CharFormatter: FatFingerCharFormatter{CryptoRand{}}}
}
// FastFingerCharFormatter formats as if written with haste, skipping characters at random
type FastFingerCharFormatter struct {
RandomDevice
}
var _ CharFormatter = FastFingerCharFormatter{}
// FormatRune at a rate of 1/6 randomly skip a rune
func (ff FastFingerCharFormatter) FormatRune(r rune) []rune {
if ff.Rand().Cmp(big.NewRat(1, 6)) < 0 {
return []rune{}
}
return []rune{r}
}
// NewFastFingerFormatter returns an initiated FastFingerCharFormatter wrapped in a CharFormatterDelegatingFormatter to produce a Formatter
func NewFastFingerFormatter() Formatter {
return &CharFormatterDelegatingFormatter{CharFormatter: FastFingerCharFormatter{CryptoRand{}}}
}
// UppercaseCharFormatter formats uppercase
type UppercaseCharFormatter struct{}
var _ CharFormatter = UppercaseCharFormatter{}
// FormatRune uppercases the rune
func (UppercaseCharFormatter) FormatRune(r rune) []rune {
return []rune{unicode.ToUpper(r)}
}
func NewUppercaseFormatter() Formatter {
return &CharFormatterDelegatingFormatter{CharFormatter: UppercaseCharFormatter{}}
}
// LowercaseCharFormatter formats lowercase
type LowercaseCharFormatter struct{}
var _ CharFormatter = LowercaseCharFormatter{}
// FormatRune the rune, but lowercase
func (LowercaseCharFormatter) FormatRune(r rune) []rune {
return []rune{unicode.ToLower(r)}
}
func NewLowercaseFormatter() Formatter {
return &CharFormatterDelegatingFormatter{CharFormatter: LowercaseCharFormatter{}}
}
// SwitchCaseCharFormatter switch the case
type SwitchCaseCharFormatter struct{}
var _ CharFormatter = SwitchCaseCharFormatter{}
// FormatRune switches case of the rune
func (SwitchCaseCharFormatter) FormatRune(r rune) []rune {
if unicode.IsUpper(r) {
return []rune{unicode.ToLower(r)}
}
return []rune{unicode.ToUpper(r)}
}
// NewSarcasticFormatter returns a CharFormatterDelegatingFormatter that wraps a
// RandomlyFormattingCharFormatter that randomly delegates to SwitchCaseCharFormatter
func NewSarcasticFormatter() Formatter {
randomFormatter := NewRandomFormatter()
randomFormatter.Other = &SwitchCaseCharFormatter{}
return &CharFormatterDelegatingFormatter{randomFormatter}
}
type swearCharFormatter struct {
RandomDevice
}
var _ CharFormatter = swearCharFormatter{
CryptoRand{},
}
func (s swearCharFormatter) FormatRune(_ rune) []rune {
letters := `#&$@%+*"`
idx := s.RandMax(len(letters))
return []rune{rune(letters[idx])}
}