76 lines
1.8 KiB
Go
76 lines
1.8 KiB
Go
package freetype
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type Emoji struct {
|
|
Codepoints []rune
|
|
Bytes int
|
|
}
|
|
|
|
var (
|
|
errNotAnEmoji = errors.New("not an emoji")
|
|
)
|
|
|
|
func inrange(val, min, max rune) bool {
|
|
return val >= min && val < max
|
|
}
|
|
|
|
// https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji/39425959
|
|
func isEmoji(chr rune) bool {
|
|
switch {
|
|
case inrange(chr, 0x1f600, 0x1f64f), // Emoticons
|
|
inrange(chr, 0x1f300, 0x1f5ff), // Misc Symbols and Pictographs
|
|
inrange(chr, 0x1f680, 0x1f6ff), // Transport and Map
|
|
inrange(chr, 0x1f1e6, 0x1f1ff), // Regional country flags
|
|
inrange(chr, 0x2600, 0x26ff), // Misc symbols
|
|
inrange(chr, 0x2700, 0x27bf), // Dingbats
|
|
inrange(chr, 0xfe00, 0xfe0f), // Variation Selectors
|
|
inrange(chr, 0x1f900, 0x1f9ff), // Supplemental Symbols and Pictographs
|
|
inrange(chr, 127000, 127600), // Various asian characters
|
|
inrange(chr, 65024, 65039), // Variation selector
|
|
inrange(chr, 9100, 9300), // Misc items
|
|
inrange(chr, 8400, 8447): // Combining Diacritical Marks for Symbols
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isZWJ(chr rune) bool {
|
|
return chr == 8205
|
|
}
|
|
|
|
func parseEmoji(str string) (Emoji, error) {
|
|
if len(str) < 1 {
|
|
return Emoji{}, errNotAnEmoji
|
|
}
|
|
|
|
emoji := Emoji{}
|
|
|
|
for _, r := range str {
|
|
// Check if rune is emoji
|
|
if !isEmoji(r) && !isZWJ(r) {
|
|
if len(emoji.Codepoints) < 1 {
|
|
return emoji, errNotAnEmoji
|
|
}
|
|
break
|
|
}
|
|
|
|
emoji.Codepoints = append(emoji.Codepoints, r)
|
|
emoji.Bytes += utf8.RuneLen(r)
|
|
}
|
|
|
|
return emoji, nil
|
|
}
|
|
|
|
func (e Emoji) String() string {
|
|
codepoints := []string{}
|
|
for _, cp := range e.Codepoints {
|
|
codepoints = append(codepoints, fmt.Sprintf("%U", cp))
|
|
}
|
|
return "Emoji(" + strings.Join(codepoints, ", ") + ")"
|
|
}
|