This repository was archived by the owner on Apr 7, 2024. It is now read-only.
forked from enescakir/emoji
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathparser.go
More file actions
158 lines (127 loc) · 3.27 KB
/
Copy pathparser.go
File metadata and controls
158 lines (127 loc) · 3.27 KB
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
package emoji
import (
"bytes"
"fmt"
"regexp"
"strings"
"unicode"
"unsafe"
)
var (
flagRegex = regexp.MustCompile(`^:flag-([a-zA-Z]{2}):$`)
)
type Replacer struct {
matched bytes.Buffer
}
func NewReplacer() *Replacer {
return &Replacer{matched: bytes.Buffer{}}
}
// Replace replaces emoji aliases (:pizza:) with unicode representation.
func (p *Replacer) Replace(input string) string {
p.matched.Reset()
return replaceInternal(input, &p.matched)
}
// Replace replaces emoji aliases (:pizza:) with unicode representation.
func Replace(input string) string {
return replaceInternal(input, &bytes.Buffer{})
}
// Parse is an alias for Replace
func Parse(input string) string {
return Replace(input)
}
// replaceInternal replaces emoji aliases (:pizza:) with unicode representation.
func replaceInternal(input string, matched *bytes.Buffer) string {
var output strings.Builder
output.Grow(len(input))
for _, r := range input {
// when it's not `:`, it might be inner or outer of the emoji alias
if r != ':' {
// if matched is empty, it's the outer of the emoji alias
if matched.Len() == 0 {
output.WriteRune(r)
continue
}
matched.WriteRune(r)
// if it's space, the alias's not valid.
// reset matched for breaking the emoji alias
if unicode.IsSpace(r) {
output.WriteString(unsafeString(matched))
matched.Reset()
}
continue
}
// r is `:` now
// if matched is empty, it's the beginning of the emoji alias
if matched.Len() == 0 {
matched.WriteByte(':')
continue
}
// it's the end of the emoji alias
match := unsafeString(matched)
matched.WriteByte(':')
alias := unsafeString(matched)
// check for emoji alias
if code, ok := Find(alias); ok {
output.WriteString(code)
matched.Reset()
continue
}
// not found any emoji
output.WriteString(match)
// it might be the beginning of the another emoji alias
matched.Reset()
matched.WriteByte(':')
}
// if matched not empty, add it to output
if matched.Len() != 0 {
output.WriteString(unsafeString(matched))
matched.Reset()
}
return output.String()
}
// Map returns the emojis map.
// Key is the alias of the emoji.
// Value is the code of the emoji.
func Map() map[string]string {
return emojiMap
}
// AppendAlias adds new emoji pair to the emojis map.
func AppendAlias(alias, code string) error {
if c, ok := emojiMap[alias]; ok {
return fmt.Errorf("emoji already exist: %q => %+q", alias, c)
}
for _, r := range alias {
if unicode.IsSpace(r) {
return fmt.Errorf("emoji alias is not valid: %q", alias)
}
}
emojiMap[alias] = code
return nil
}
// Exist checks existence of the emoji by alias.
func Exist(alias string) bool {
_, ok := Find(alias)
return ok
}
// Find returns the emoji code by alias.
func Find(alias string) (string, bool) {
if code, ok := emojiMap[alias]; ok {
return code, true
}
if flag := checkFlag(alias); len(flag) > 0 {
return flag, true
}
return "", false
}
// checkFlag finds flag emoji for `flag-[CODE]` pattern
func checkFlag(alias string) string {
if matches := flagRegex.FindStringSubmatch(alias); len(matches) == 2 {
flag, _ := CountryFlag(matches[1])
return flag.String()
}
return ""
}
func unsafeString(matched *bytes.Buffer) string {
buf := matched.Bytes()
return *(*string)(unsafe.Pointer(&buf))
}