freetype/emoji.go

77 lines
1.8 KiB
Go
Raw Normal View History

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, ", ") + ")"
}