-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathembed.go
110 lines (89 loc) · 1.97 KB
/
embed.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
package zwfp
import (
"fmt"
"strings"
)
// Zero width non-printing characters
const (
zwsp = '\u200B' // 1
zwnj = '\u200C' // 0
zwj = '\u200D' // letter
zwnb = '\uFEFF' // word
)
// toBits converts each character in the string to base 2 form
func toBits(s string) []string {
var bits []string
for _, c := range s {
bits = append(bits, fmt.Sprintf("%b", c))
}
return bits
}
// convert converts binary string to zero-width string
// 1 -> zwsp
// 0 -> zwnj
func convertLetter(s string) string {
var sb strings.Builder
for _, c := range s {
if c == '0' {
sb.WriteRune(zwnj)
continue
}
sb.WriteRune(zwsp)
}
return sb.String()
}
// convertWord converts a word to zero-width string
func convertWord(s string) string {
bits := toBits(s)
var zws []string
for _, b := range bits {
zws = append(zws, convertLetter(b))
}
// join each letter by zero-width joiner
return strings.Join(zws, string(zwj))
}
// toZeroWidth converts string s to zero width characters
func toZeroWidth(s string) string {
// trim spaces across edges
s = strings.TrimSpace(s)
// split to words separated by space
words := strings.Split(s, " ")
var zwWords []string
for _, w := range words {
zwWords = append(zwWords, convertWord(w))
}
// join each word by zero-width no break
return strings.Join(zwWords, string(zwnb))
}
// Embed embeds the key into data using zero-width characters
func Embed(data, key string) string {
zwKey := toZeroWidth(key)
var zwRKey []rune
for _, c := range zwKey {
zwRKey = append(zwRKey, c)
}
var t int
var embed []rune
for i, c := range data {
if i == 0 {
embed = append(embed, c)
}
if t < len(zwRKey) {
embed = append(embed, zwRKey[t])
t++
}
if i != 0 {
embed = append(embed, c)
}
}
if t < len(zwRKey) {
if len(embed) > 0 {
lb := embed[len(embed)-1]
embed = append(embed[:len(embed)-1], zwRKey[t:]...)
embed = append(embed, lb)
} else {
embed = append(embed, zwRKey[t:]...)
}
}
return string(embed)
}