This commit is contained in:
cdle
2023-06-05 16:05:25 +08:00
parent dab997e54a
commit 0599f15f9e
6 changed files with 47750 additions and 1 deletions
+13
View File
@@ -7,6 +7,8 @@ import (
"regexp"
"strconv"
"strings"
"github.com/cdle/sillyplus/emoji"
)
type Strings struct {
@@ -159,3 +161,14 @@ func convertParams(params map[string]interface{}) map[string]string {
}
return result
}
func (sender *Strings) ReplaceEmojis(str string, f func([]string) string) string {
return emoji.ReplaceEmojisWithFunc(str, func(e emoji.Emoji) string {
return f(e.CodePoint2)
})
}
// `\[emoji=([0-9A-Z]{4})\]`
func (sender *Strings) ReplaceToEmojis(str string, pattern string) string {
return emoji.ReplaceToEmojis(str, pattern)
}
+47384
View File
File diff suppressed because it is too large Load Diff
+176
View File
@@ -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
View File
@@ -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
}
+3 -1
View File
@@ -14,6 +14,7 @@ require (
github.com/dop251/goja v0.0.0-20230427124612-428fc442ff5f
github.com/dop251/goja_nodejs v0.0.0-20230322100729-2550c7b6c124
github.com/elastic/go-elasticsearch/v6 v6.8.5
github.com/forPelevin/gomoji v1.1.8
github.com/gin-gonic/gin v1.8.1
github.com/go-redis/redis/v8 v8.11.5
github.com/goccy/go-json v0.9.7
@@ -23,7 +24,6 @@ require (
github.com/robfig/cron/v3 v3.0.1
github.com/stretchr/testify v1.8.0
golang.org/x/net v0.4.0
gopkg.in/yaml.v2 v2.4.0
)
require (
@@ -31,6 +31,8 @@ require (
github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+4
View File
@@ -62,6 +62,8 @@ github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/forPelevin/gomoji v1.1.8 h1:JElzDdt0TyiUlecy6PfITDL6eGvIaxqYH1V52zrd0qQ=
github.com/forPelevin/gomoji v1.1.8/go.mod h1:8+Z3KNGkdslmeGZBC3tCrwMrcPy5GRzAD+gL9NAwMXg=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
@@ -199,6 +201,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=