-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathcommon.go
137 lines (115 loc) · 3.53 KB
/
common.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
// SPDX-License-Identifier: MIT OR Unlicense
package str
import (
"strings"
"unicode"
)
// RemoveStringDuplicates is a simple helper method that removes duplicates from
// any given str slice and then returns a nice duplicate free str slice
func RemoveStringDuplicates(elements []string) []string {
var encountered = map[string]bool{}
var result []string
for v := range elements {
if !encountered[elements[v]] {
encountered[elements[v]] = true
result = append(result, elements[v])
}
}
return result
}
// Contains checks the supplied slice of string for the existence
// of a string and returns true if found, and false otherwise
func Contains(elements []string, needle string) bool {
for _, v := range elements {
if needle == v {
return true
}
}
return false
}
// PermuteCase given a str returns a slice containing all possible case permutations
// of that str such that input of foo will return
// foo Foo fOo FOo foO FoO fOO FOO
// Note that very long inputs can produce an enormous amount of
// results in the returned slice OR result in an overflow and return nothing
func PermuteCase(input string) []string {
l := len(input)
max := 1 << l
var combinations []string
for i := 0; i < max; i++ {
s := ""
for idx, ch := range input {
if (i & (1 << idx)) == 0 {
s += strings.ToUpper(string(ch))
} else {
s += strings.ToLower(string(ch))
}
}
combinations = append(combinations, s)
}
return RemoveStringDuplicates(combinations)
}
// PermuteCaseFolding given a str returns a slice containing all possible case permutations
// with characters being folded such that S will return S s ſ
func PermuteCaseFolding(input string) []string {
combinations := PermuteCase(input)
var combos []string
for _, combo := range combinations {
for index, runeValue := range combo {
for _, p := range AllSimpleFold(runeValue) {
combos = append(combos, combo[:index]+string(p)+combo[index+len(string(runeValue)):])
}
}
}
return RemoveStringDuplicates(combos)
}
// AllSimpleFold given an input rune return a rune slice containing
// all of the possible simple fold
func AllSimpleFold(input rune) []rune {
var res []rune
// This works for getting all folded representations
// but feels totally wrong due to the bailout break.
// That said its simpler than a while with checks
// Investigate https://github.com/golang/go/blob/master/src/regexp/syntax/prog.go#L215 as a possible way to implement
for i := 0; i < 255; i++ {
input = unicode.SimpleFold(input)
if containsRune(res, input) {
break
}
res = append(res, input)
}
return res
}
func containsRune(elements []rune, needle rune) bool {
for _, v := range elements {
if needle == v {
return true
}
}
return false
}
// IsSpace checks bytes MUST which be UTF-8 encoded for a space
// List of spaces detected (same as unicode.IsSpace):
// '\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP).
// N.B only two bytes are required for these cases. If we decided
// to support spaces like ',' then we'll need more bytes.
func IsSpace(firstByte, nextByte byte) bool {
switch {
case (9 <= firstByte) && (firstByte <= 13): // \t, \n, \f, \r
return true
case firstByte == 32: // SPACE
return true
case firstByte == 194:
if nextByte == 133 { // NEL
return true
} else if nextByte == 160 { // NBSP
return true
}
}
return false
}
// StartOfRune a byte and returns true if its the start of a multibyte
// character or a single byte character otherwise false
func StartOfRune(b byte) bool {
return (b < (0b1 << 7)) || ((0b11 << 6) < b)
}