x
This commit is contained in:
+47384
File diff suppressed because it is too large
Load Diff
+176
@@ -0,0 +1,176 @@
|
||||
package emoji
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i, emoji := range emojiMap {
|
||||
code_points := []string{}
|
||||
for _, v := range strings.Split(emojiMap[i].CodePoint, " ") {
|
||||
switch len(v) {
|
||||
case 4:
|
||||
code_points = append(code_points, v)
|
||||
case 5:
|
||||
code_points = append(code_points, transfer(v)...)
|
||||
default:
|
||||
}
|
||||
}
|
||||
if len(code_points) == 0 {
|
||||
for _, v := range strings.Split(emojiMap[i].CodePoint, "-") {
|
||||
switch len(v) {
|
||||
case 4:
|
||||
code_points = append(code_points, v)
|
||||
case 5:
|
||||
code_points = append(code_points, transfer(v)...)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(code_points) == 0 {
|
||||
delete(emojiMap, i)
|
||||
} else {
|
||||
emoji.CodePoint2 = code_points
|
||||
emojiMap[i] = emoji
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertRegex(input string) string {
|
||||
// 定义要转义的字符集合
|
||||
escapeSet := []string{"\\", "[", "]", "(", ")", "{", "}", ".", "*", "+", "?", "^", "$", "|"}
|
||||
|
||||
// 定义正则表达式模式和替换字符串
|
||||
var pattern = `%s`
|
||||
var replaceStr = `([0-9A-Za-z]{4})`
|
||||
|
||||
// 对可能引起正则表达式冲突的字符进行转义
|
||||
for _, esc := range escapeSet {
|
||||
input = strings.ReplaceAll(input, esc, "\\"+esc)
|
||||
}
|
||||
|
||||
// 将子匹配内容替换为指定格式的正则表达式
|
||||
replaced := strings.ReplaceAll(input, pattern, replaceStr)
|
||||
|
||||
// 返回转换结果和是否大写的标记
|
||||
return replaced
|
||||
}
|
||||
|
||||
// \[emoji=[0-9A-Z]{4}\]
|
||||
func ReplaceToEmojis(str string, pattern string) string {
|
||||
format := pattern
|
||||
pattern = ConvertRegex(pattern)
|
||||
str = regexp.MustCompile("[0-9]"+pattern+pattern).ReplaceAllStringFunc(str, func(s string) string {
|
||||
if !strings.EqualFold(strings.ToUpper(s[1:]), strings.ToUpper(fmt.Sprintf(format+format, "FE0F", "20E3"))) { //"[emoji=FE0F][emoji=20E3]"
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf(format, fmt.Sprintf("%04X", s[0])) + s[1:]
|
||||
})
|
||||
res := str
|
||||
h := func(ssr *[]string) string {
|
||||
chs := []string{}
|
||||
ch := ""
|
||||
l := 100
|
||||
lft := []string{}
|
||||
again:
|
||||
for j := range emojiMap {
|
||||
ok, left := matchPrefix(emojiMap[j].CodePoint2, *ssr)
|
||||
if ok {
|
||||
if ln := len(left); ln < l {
|
||||
ch = emojiMap[j].Character
|
||||
l = ln
|
||||
lft = left
|
||||
}
|
||||
}
|
||||
}
|
||||
if ch != "" {
|
||||
chs = append(chs, ch)
|
||||
}
|
||||
if len(lft) != 0 && ch != "" {
|
||||
ch = ""
|
||||
l = 100
|
||||
*ssr = lft
|
||||
lft = []string{}
|
||||
goto again
|
||||
}
|
||||
return strings.Join(chs, "")
|
||||
}
|
||||
sss := regexp.MustCompile(pattern).FindAllStringSubmatchIndex(str, -1)
|
||||
ssr := []string{}
|
||||
ssrs := []string{}
|
||||
e := -1
|
||||
for i := range sss {
|
||||
ss := sss[i]
|
||||
a, b, c, d := ss[0], ss[1], ss[2], ss[3]
|
||||
|
||||
//结算
|
||||
if e != a && len(ssr) != 0 {
|
||||
rs := h(&ssr)
|
||||
res = strings.Replace(res, strings.Join(ssrs, ""), rs, 1)
|
||||
ssr = []string{}
|
||||
ssrs = []string{}
|
||||
e = -1
|
||||
}
|
||||
|
||||
ssrs = append(ssrs, str[a:b])
|
||||
// if upper {
|
||||
// ssr = append(ssr, str[c:d])
|
||||
// } else {
|
||||
ssr = append(ssr, strings.ToUpper(str[c:d]))
|
||||
// }
|
||||
e = b
|
||||
}
|
||||
if len(ssr) != 0 {
|
||||
rs := h(&ssr)
|
||||
res = strings.Replace(res, strings.Join(ssrs, ""), rs, 1)
|
||||
e = -1
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func transfer(str string) []string {
|
||||
// 将输入字符串解析为十六进制数
|
||||
unicodeValue, err := strconv.ParseUint(str, 16, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// 将 Unicode 编码值转换为 UTF-16 编码单元
|
||||
utf16Units := utf16.Encode([]rune{rune(unicodeValue)})
|
||||
|
||||
// 将 UTF-16 编码单元格式化为字符串,并返回字符串切片
|
||||
return []string{fmt.Sprintf("%04X", utf16Units[0]), fmt.Sprintf("%04X", utf16Units[1])}
|
||||
}
|
||||
|
||||
func matchPrefix(s1 []string, s2 []string) (bool, []string) {
|
||||
if len(s1) > len(s2) {
|
||||
return false, s2
|
||||
}
|
||||
for i := range s1 {
|
||||
if s1[i] != s2[i] {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, s2[len(s1):]
|
||||
}
|
||||
|
||||
func RuneToHx(a rune) string {
|
||||
return fmt.Sprintf("%04X", a)
|
||||
}
|
||||
|
||||
func HexToRune(hexStr string) (rune, error) {
|
||||
// 解析十六进制字符串,获取对应的无符号整数
|
||||
u, err := strconv.ParseUint(hexStr, 16, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 将无符号整数转换为 rune 类型的 Unicode 编码值
|
||||
r := rune(u)
|
||||
|
||||
// 返回转换结果
|
||||
return r, nil
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
package emoji
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/rivo/uniseg"
|
||||
)
|
||||
|
||||
// errors
|
||||
var (
|
||||
ErrStrNotEmoji = errors.New("the string is not emoji")
|
||||
)
|
||||
|
||||
// Emoji is an entity that represents comprehensive emoji info.
|
||||
type Emoji struct {
|
||||
Slug string `json:"slug"`
|
||||
Character string `json:"character"`
|
||||
UnicodeName string `json:"unicode_name"`
|
||||
CodePoint string `json:"code_point"`
|
||||
CodePoint2 []string `json:"code_points"`
|
||||
Group string `json:"group"`
|
||||
SubGroup string `json:"sub_group"`
|
||||
}
|
||||
|
||||
// ContainsEmoji checks whether given string contains emoji or not. It uses local emoji list as provider.
|
||||
func ContainsEmoji(s string) bool {
|
||||
for _, r := range s {
|
||||
if _, ok := emojiMap[string(r)]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
gr := uniseg.NewGraphemes(s)
|
||||
for gr.Next() {
|
||||
if _, ok := emojiMap[gr.Str()]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// AllEmojis gets all emojis from provider.
|
||||
func AllEmojis() []Emoji {
|
||||
return emojiMapToSlice(emojiMap)
|
||||
}
|
||||
|
||||
// RemoveEmojis removes all emojis from the s string and returns a new string.
|
||||
func RemoveEmojis(s string) string {
|
||||
return ReplaceEmojisWithFunc(s, nil)
|
||||
}
|
||||
|
||||
// ReplaceEmojisWith replaces all emojis from the s string with the specified rune and returns a new string.
|
||||
func ReplaceEmojisWith(s string, c rune) string {
|
||||
replacerStr := string(c)
|
||||
return ReplaceEmojisWithFunc(s, func(em Emoji) string {
|
||||
return replacerStr
|
||||
})
|
||||
}
|
||||
|
||||
// ReplaceEmojisWithSlug replaces all emojis from the s string with the emoji's slug and returns a new string.
|
||||
func ReplaceEmojisWithSlug(s string) string {
|
||||
return ReplaceEmojisWithFunc(s, func(em Emoji) string {
|
||||
return em.Slug
|
||||
})
|
||||
}
|
||||
|
||||
type replacerFn func(e Emoji) string
|
||||
|
||||
// ReplaceEmojisWithFunc replaces all emojis from the s string with the result of the replacerFn function and returns a new string.
|
||||
func ReplaceEmojisWithFunc(s string, replacer replacerFn) string {
|
||||
cleanBuf := bytes.Buffer{}
|
||||
|
||||
gr := uniseg.NewGraphemes(s)
|
||||
for gr.Next() {
|
||||
em, ok := emojiMap[gr.Str()]
|
||||
if !ok {
|
||||
cleanBuf.Write(gr.Bytes())
|
||||
continue
|
||||
}
|
||||
|
||||
if replacer != nil {
|
||||
cleanBuf.WriteString(replacer(em))
|
||||
}
|
||||
}
|
||||
|
||||
res := cleanBuf
|
||||
res.Reset()
|
||||
for _, r := range cleanBuf.String() {
|
||||
em, ok := emojiMap[string(r)]
|
||||
if !ok {
|
||||
res.WriteRune(r)
|
||||
continue
|
||||
}
|
||||
|
||||
if replacer != nil {
|
||||
res.WriteString(replacer(em))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.TrimFunc(res.String(), func(r rune) bool {
|
||||
return unicode.IsSpace(r) || !unicode.IsGraphic(r) || !unicode.IsPrint(r) || unicode.In(r, unicode.Variation_Selector)
|
||||
})
|
||||
}
|
||||
|
||||
// GetInfo returns a gomoji.Emoji model representation of provided emoji.
|
||||
// If the emoji was not found, it returns the gomoji.ErrStrNotEmoji error
|
||||
func GetInfo(emoji string) (Emoji, error) {
|
||||
em, ok := emojiMap[emoji]
|
||||
if !ok {
|
||||
return Emoji{}, ErrStrNotEmoji
|
||||
}
|
||||
|
||||
return em, nil
|
||||
}
|
||||
|
||||
// CollectAll finds all emojis in given string. Unlike FindAll, this does not
|
||||
// distinct repeating occurrences of emoji. If there are no emojis it returns a nil-slice.
|
||||
func CollectAll(s string) []Emoji {
|
||||
var emojis []Emoji
|
||||
|
||||
gr := uniseg.NewGraphemes(s)
|
||||
for gr.Next() {
|
||||
if em, ok := emojiMap[gr.Str()]; ok {
|
||||
emojis = append(emojis, em)
|
||||
continue
|
||||
}
|
||||
|
||||
start, end := gr.Positions()
|
||||
for _, r := range s[start:end] {
|
||||
if em, ok := emojiMap[string(r)]; ok {
|
||||
emojis = append(emojis, em)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return emojis
|
||||
}
|
||||
|
||||
// FindAll finds all emojis in given string. If there are no emojis it returns a nil-slice.
|
||||
func FindAll(s string) []Emoji {
|
||||
emojis := make(map[string]Emoji)
|
||||
|
||||
gr := uniseg.NewGraphemes(s)
|
||||
for gr.Next() {
|
||||
if em, ok := emojiMap[gr.Str()]; ok {
|
||||
emojis[gr.Str()] = em
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range s {
|
||||
if em, ok := emojiMap[string(r)]; ok {
|
||||
emojis[string(r)] = em
|
||||
}
|
||||
}
|
||||
|
||||
return emojiMapToSlice(emojis)
|
||||
}
|
||||
|
||||
func emojiMapToSlice(em map[string]Emoji) []Emoji {
|
||||
var emojis []Emoji
|
||||
for _, emoji := range em {
|
||||
emojis = append(emojis, emoji)
|
||||
}
|
||||
|
||||
return emojis
|
||||
}
|
||||
Reference in New Issue
Block a user