-
Notifications
You must be signed in to change notification settings - Fork 0
/
thespine.go
140 lines (118 loc) · 2.84 KB
/
thespine.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
package thespine
import (
"errors"
"strings"
"unicode/utf8"
)
// theSize represents the size of grouping used by the anagram encode/decode.
const theSize = 3
// ErrInvalidString represents an error for invalid UTF-8 string.
var ErrInvalidString = errors.New("invalid string")
// Decode takes a UTF-8 string as an input and decodes the anagram.
// Error returned in case of an invalid UTF-8 string.
func Decode(s string) (string, error) {
if !utf8.ValidString(s) {
return "", ErrInvalidString
}
sr := []rune(s)
l := len(sr)
if l <= theSize {
return s, nil
}
gc := (l + theSize - 1) / theSize
g := make([][]rune, gc)
for i := range gc {
si := l - (i+1)*theSize
ei := l - i*theSize
if si < 0 {
si = 0
}
g[i] = sr[si:ei]
}
return runestring(g), nil
}
// Encode takes a UTF-8 string as an input and generates an anagram out of it.
// Error returned in case of an invalid UTF-8 string.
func Encode(s string) (string, error) {
if !utf8.ValidString(s) {
return "", ErrInvalidString
}
sr := []rune(s)
l := len(sr)
if l <= theSize {
return s, nil
}
gc := (l + theSize - 1) / theSize
g := make([][]rune, gc)
for i := range gc {
si := i * theSize
ei := (i + 1) * theSize
if ei > l {
ei = l
}
g[i] = sr[si:ei]
}
for i, j := 0, len(g)-1; i < j; i, j = i+1, j-1 {
g[i], g[j] = g[j], g[i]
}
return runestring(g), nil
}
// EncodeText takes a UTF-8 string as an input, splits it by whitespace and runs an anagram for each word.
// Error returned in case of an invalid UTF-8 string.
func EncodeText(s string) (string, error) {
if s == "" {
return "", nil
}
var builder strings.Builder
ws := strings.Split(s, " ")
for i, w := range ws {
if w == "" {
continue // Skip empty strings or preserve them, depending on requirements
}
ew, err := Encode(w)
if err != nil {
return "", err
}
builder.WriteString(ew)
if i != len(ws)-1 {
builder.WriteString(" ")
}
}
return builder.String(), nil
}
// DecodeText takes a UTF-8 string as an input, splits it by whitespace and decodes each anagram word-by-word.
// Error returned in case of an invalid UTF-8 string.
func DecodeText(s string) (string, error) {
if s == "" {
return "", nil
}
var builder strings.Builder
ws := strings.Split(s, " ")
for i, w := range ws {
if w == "" {
continue // Skip empty strings or preserve them, depending on requirements
}
ew, err := Decode(w)
if err != nil {
return "", err
}
builder.WriteString(ew)
if i < len(ws)-1 {
builder.WriteString(" ")
}
}
return builder.String(), nil
}
func runestring(r [][]rune) string {
// Calculate total capacity needed
totalCap := 0
for _, runes := range r {
totalCap += len(runes)
}
builder := strings.Builder{}
builder.Grow(totalCap) // Pre-allocate exact size needed
for _, runes := range r {
builder.WriteString(string(runes))
}
return builder.String()
}