mirror of
https://github.com/fumiama/emozi.git
synced 2026-06-05 00:32:48 +08:00
feat(coder): finish decode
This commit is contained in:
@@ -15,7 +15,7 @@ package emozi
|
||||
|
||||
// 部首后备 内嵌的部首到颜文字的映射, 是第二优先查询顺位. 第一顺位是数据库的部首表. 第三位是回落到 🈳️.
|
||||
var 部首后备 = map[rune]string{ {{range .}}
|
||||
'{{.R}}': "🈳️",{{end}}
|
||||
'{{.R}}': 空,{{end}}
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
116
coder.go
116
coder.go
@@ -13,15 +13,16 @@ import (
|
||||
|
||||
// Coder encoder/decoder
|
||||
type Coder struct {
|
||||
mu sync.RWMutex
|
||||
db sql.Sqlite
|
||||
字表缓存 map[rune][]字表
|
||||
部首缓存 map[rune]string
|
||||
isRandom bool
|
||||
mu sync.RWMutex
|
||||
db sql.Sqlite
|
||||
字表缓存 map[rune][]字表
|
||||
逆字表缓存 map[int64][]rune
|
||||
部首缓存 map[rune]string
|
||||
逆部首缓存 map[string][]rune
|
||||
}
|
||||
|
||||
// NewCoder israndom 随机挑选声母韵母的颜文字, 否则固定使用第一个
|
||||
func NewCoder(israndom bool, cachettl time.Duration) (c Coder, err error) {
|
||||
func NewCoder(cachettl time.Duration) (c Coder, err error) {
|
||||
if _, err = os.Stat(EmoziDatabasePath); err != nil {
|
||||
err = os.WriteFile(EmoziDatabasePath, 字数据库, 0644)
|
||||
if err != nil {
|
||||
@@ -30,8 +31,9 @@ func NewCoder(israndom bool, cachettl time.Duration) (c Coder, err error) {
|
||||
}
|
||||
c.db.DBPath = EmoziDatabasePath
|
||||
c.字表缓存 = make(map[rune][]字表, 4096)
|
||||
c.逆字表缓存 = make(map[int64][]rune, 4096)
|
||||
c.部首缓存 = make(map[rune]string, 4096)
|
||||
c.isRandom = israndom
|
||||
c.逆部首缓存 = make(map[string][]rune, 4096)
|
||||
err = c.db.Open(cachettl)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -56,19 +58,23 @@ func NewCoder(israndom bool, cachettl time.Duration) (c Coder, err error) {
|
||||
func (c *Coder) Close() error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.字表缓存 = nil
|
||||
c.逆字表缓存 = nil
|
||||
c.部首缓存 = nil
|
||||
c.逆部首缓存 = nil
|
||||
return c.db.Close()
|
||||
}
|
||||
|
||||
// Encode 从汉字序列生成 EmoziString 返回 EmoziString 多音字选择数列表
|
||||
func (c *Coder) Encode(s string, selections ...int) (EmoziString, []int, error) {
|
||||
func (c *Coder) Encode(enableRandom bool, s string, selections ...int) (EmoziString, []int, error) {
|
||||
sb := strings.Builder{}
|
||||
lstbuf := make([]字表, 0, len(s)/2)
|
||||
var lst []字表
|
||||
write := func(x *字表) {
|
||||
sb.WriteString(c.查声母(x.S))
|
||||
sb.WriteString(c.查韵母(x.Y))
|
||||
sb.WriteString(c.查声调(x.T))
|
||||
sb.WriteString(c.查部首(x.R))
|
||||
sb.WriteString(c.声母(enableRandom, x.S))
|
||||
sb.WriteString(c.韵母(enableRandom, x.Y))
|
||||
sb.WriteString(c.声调(enableRandom, x.T))
|
||||
sb.WriteString(c.部首(x.R))
|
||||
}
|
||||
多音字计数 := 0
|
||||
多音字数表 := []int{}
|
||||
@@ -104,6 +110,92 @@ func (c *Coder) Encode(s string, selections ...int) (EmoziString, []int, error)
|
||||
return WrapRawEmoziString(sb.String()), 多音字数表, nil
|
||||
}
|
||||
|
||||
// Decode 从 EmoziString 解码得到可能的文字序列
|
||||
func (c *Coder) Decode(es EmoziString, forcedecode bool) (string, error) {
|
||||
if !es.IsValid() && !forcedecode {
|
||||
return "", ErrInvalidEmoziString
|
||||
}
|
||||
s := ""
|
||||
if forcedecode {
|
||||
s = string(es)
|
||||
} else {
|
||||
s = es.String()
|
||||
}
|
||||
lstbuf := make([]字表, 0, len(s)/8)
|
||||
read := func(s string) (string, int) {
|
||||
sum := 0
|
||||
sm, n := c.逆声母(s)
|
||||
if n == 0 {
|
||||
return "", 0
|
||||
}
|
||||
sum += n
|
||||
ym, n := c.逆韵母(s[sum:])
|
||||
if n == 0 {
|
||||
return "", 0
|
||||
}
|
||||
sum += n
|
||||
t, n := c.逆声调(s[sum:])
|
||||
if n == 0 {
|
||||
return "", 0
|
||||
}
|
||||
sum += n
|
||||
rs, n := c.逆部首(s[sum:])
|
||||
if n == 0 {
|
||||
return "", 0
|
||||
}
|
||||
sum += n
|
||||
var possibles []rune
|
||||
var err error
|
||||
if len(rs) == 0 { // 意符为空
|
||||
possibles, lstbuf, err = c.逆字(sm, ym, t, 0, lstbuf)
|
||||
if err != nil {
|
||||
return "[]", sum
|
||||
}
|
||||
} else {
|
||||
var revr []rune
|
||||
for i := 0; i < len(rs); i++ {
|
||||
revr, lstbuf, err = c.逆字(sm, ym, t, rs[i], lstbuf)
|
||||
if err != nil || len(revr) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(possibles) == 0 {
|
||||
possibles = revr
|
||||
} else {
|
||||
possibles = append(possibles, revr...)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(possibles) == 0 {
|
||||
return "[]", sum
|
||||
}
|
||||
if len(possibles) == 1 {
|
||||
return string(possibles[0]), sum
|
||||
}
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString("[")
|
||||
sb.WriteRune(possibles[0])
|
||||
for _, r := range possibles[1:] {
|
||||
sb.WriteString("|")
|
||||
sb.WriteRune(r)
|
||||
}
|
||||
sb.WriteString("]")
|
||||
return sb.String(), sum
|
||||
}
|
||||
sb := strings.Builder{}
|
||||
sum := 0
|
||||
for sum < len(s) {
|
||||
ch, n := read(s[sum:])
|
||||
if n <= 0 {
|
||||
sb.WriteByte(s[sum])
|
||||
sum++
|
||||
continue
|
||||
}
|
||||
sum += n
|
||||
sb.WriteString(ch)
|
||||
}
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
// AddChar 向主库添加一个新字
|
||||
//
|
||||
// w: 字, r: 部首, p: 不带声调的拼音(可空), f: 带声调的拼音
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
)
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
c, err := NewCoder(false, time.Minute)
|
||||
c, err := NewCoder(time.Minute)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
es, lst, err := c.Encode("你好,世界!看看多音字:行。")
|
||||
es, lst, err := c.Encode(false, "你好,世界!看看多音字:行。")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -21,7 +21,7 @@ func TestEncode(t *testing.T) {
|
||||
if len(lst) != 1 && lst[0] != 2 {
|
||||
t.Fail()
|
||||
}
|
||||
es, lst, err = c.Encode("你好,世界!指定多音字:银行行。", 1, 0)
|
||||
es, lst, err = c.Encode(false, "你好,世界!指定多音字:银行行。", 1, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -33,3 +33,37 @@ func TestEncode(t *testing.T) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
c, err := NewCoder(time.Minute)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := "你好,世界!看看多音字:行。"
|
||||
es, lst, err := c.Encode(false, s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(es.String(), lst)
|
||||
ds, err := c.Decode(es, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(ds)
|
||||
if ds != "[你|儗]好,世[界|畍]!看看多音字:[行|行]。" {
|
||||
t.Fatal("got", ds)
|
||||
}
|
||||
es, lst, err = c.Encode(false, "你好,世界!指定多音字:银行行。", 1, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(es.String(), lst)
|
||||
ds, err = c.Decode(es, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(ds)
|
||||
if ds != "[你|儗]好,世[界|畍]![指|抧|扺]定多音字:[銀|银]行行。" {
|
||||
t.Fatal("got", ds)
|
||||
}
|
||||
}
|
||||
|
||||
86
data.go
86
data.go
@@ -2,7 +2,9 @@ package emozi
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 字数据库 数据来自 https://github.com/shuowenjiezi/shuowen
|
||||
@@ -11,7 +13,7 @@ import (
|
||||
var 字数据库 []byte
|
||||
|
||||
// DatabasePath 字数据库的路径 如找不到会向对应路径写入内嵌的字数据库
|
||||
var EmoziDatabasePath = "字a.db"
|
||||
var EmoziDatabasePath = "字.db"
|
||||
|
||||
const (
|
||||
主字表名 = "emozi"
|
||||
@@ -19,6 +21,10 @@ const (
|
||||
部首表名 = "radcl"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoSuchChar = errors.New("no such char")
|
||||
)
|
||||
|
||||
// 字表 emozi表 定义
|
||||
type 字表 struct {
|
||||
ID int64 // ID 高 32 位 W 的 rune, 低 32 位 保留8 S8 Y8 T8
|
||||
@@ -35,33 +41,105 @@ func 字表ID(w rune, s 声母枚举, y 韵母枚举, t 声调枚举) int64 {
|
||||
return int64((uint64(w) << 32) | (uint64(s) << 16) | (uint64(y) << 8) | (uint64(t)))
|
||||
}
|
||||
|
||||
// 逆字ID 同声母 韵母 声调 部首的字的集合
|
||||
func 逆字ID(s 声母枚举, y 韵母枚举, t 声调枚举, r rune) int64 {
|
||||
return int64((uint64(r) << 32) | (uint64(s) << 16) | (uint64(y) << 8) | (uint64(t)))
|
||||
}
|
||||
|
||||
// 查字 返回 lst lstbuf error
|
||||
func (c *Coder) 查字(ch rune, lstbuf []字表) ([]字表, []字表, error) {
|
||||
c.mu.RLock()
|
||||
lst, ok := c.字表缓存[ch]
|
||||
c.mu.RUnlock()
|
||||
if ok {
|
||||
if len(lst) == 0 {
|
||||
return nil, lstbuf, ErrNoSuchChar
|
||||
}
|
||||
return lst, lstbuf, nil
|
||||
}
|
||||
lstbuf = lstbuf[:0]
|
||||
x := 字表{}
|
||||
q := "WHERE W=" + strconv.Itoa(int(ch))
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
err := c.db.FindFor(附字表名, &x, "WHERE W="+strconv.Itoa(int(ch)), func() error {
|
||||
err := c.db.FindFor(附字表名, &x, q, func() error {
|
||||
lstbuf = append(lstbuf, x)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
lstbuf = lstbuf[:0]
|
||||
err = c.db.FindFor(主字表名, &x, "WHERE W="+strconv.Itoa(int(ch)), func() error {
|
||||
err = c.db.FindFor(主字表名, &x, q, func() error {
|
||||
lstbuf = append(lstbuf, x)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
c.字表缓存[ch] = nil
|
||||
return nil, lstbuf, err
|
||||
}
|
||||
if len(lstbuf) == 0 {
|
||||
c.字表缓存[ch] = nil
|
||||
return nil, lstbuf, ErrNoSuchChar
|
||||
}
|
||||
lstsave := make([]字表, len(lstbuf))
|
||||
copy(lstsave, lstbuf)
|
||||
c.字表缓存[ch] = lstsave
|
||||
return lstbuf, lstbuf, err
|
||||
return lstbuf, lstbuf, nil
|
||||
}
|
||||
|
||||
// 逆字 逆查匹配的字
|
||||
func (c *Coder) 逆字(s 声母枚举, y 韵母枚举, t 声调枚举, r rune, lstbuf []字表) ([]rune, []字表, error) {
|
||||
id := 逆字ID(s, y, t, r)
|
||||
c.mu.RLock()
|
||||
matches, ok := c.逆字表缓存[id]
|
||||
c.mu.RUnlock()
|
||||
if ok {
|
||||
if len(matches) == 0 {
|
||||
return nil, lstbuf, ErrNoSuchChar
|
||||
}
|
||||
return matches, lstbuf, nil
|
||||
}
|
||||
lstbuf = lstbuf[:0]
|
||||
x := 字表{}
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString("WHERE S=")
|
||||
sb.WriteString(strconv.Itoa(int(s)))
|
||||
sb.WriteString(" AND Y=")
|
||||
sb.WriteString(strconv.Itoa(int(y)))
|
||||
sb.WriteString(" AND T=")
|
||||
sb.WriteString(strconv.Itoa(int(t)))
|
||||
if r != 0 {
|
||||
sb.WriteString(" AND R=")
|
||||
sb.WriteString(strconv.Itoa(int(r)))
|
||||
}
|
||||
q := sb.String()
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
err := c.db.FindFor(附字表名, &x, q, func() error {
|
||||
lstbuf = append(lstbuf, x)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
lstbuf = lstbuf[:0]
|
||||
err = c.db.FindFor(主字表名, &x, q, func() error {
|
||||
lstbuf = append(lstbuf, x)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
c.逆字表缓存[id] = nil
|
||||
return nil, lstbuf, err
|
||||
}
|
||||
if len(lstbuf) == 0 {
|
||||
c.逆字表缓存[id] = nil
|
||||
return nil, lstbuf, ErrNoSuchChar
|
||||
}
|
||||
rs := make([]rune, len(lstbuf))
|
||||
for i, x := range lstbuf {
|
||||
rs[i] = x.W
|
||||
}
|
||||
c.逆字表缓存[id] = rs
|
||||
return rs, lstbuf, nil
|
||||
}
|
||||
|
||||
// 从表 从部首表
|
||||
|
||||
56
define.go
56
define.go
@@ -1,8 +1,6 @@
|
||||
package emozi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
base14 "github.com/fumiama/go-base16384"
|
||||
)
|
||||
|
||||
@@ -11,9 +9,9 @@ type 声母枚举 uint8
|
||||
// String 国际音标
|
||||
func (sm 声母枚举) String() string {
|
||||
a := sm * 3
|
||||
b := a + 3
|
||||
b := a + [...]声母枚举{1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 3, 1, 2, 3, 1, 1, 2, 3, 1, 1, 1, 1, 1}[sm]
|
||||
s := []rune("p pʰ m f t tʰ n l k kʰ x tɕ tɕʰɕ ʈʂ ʈʂʰʂ ɻ ts tsʰs j w ɥ 0 ")[a:b]
|
||||
return strings.TrimSpace(string(s))
|
||||
return string(s)
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -88,6 +86,33 @@ var 声母 = [...][]string{
|
||||
{"🐑", "🐐", "🦷", "💊", "🧂"}, {"🧦", "🌫️", "🕸️", "🥣"}, {"🐟", "🌧️", "🐠"}, {"🪑", "💺"},
|
||||
}
|
||||
|
||||
func 低阶逆初始化(表 [][]string, 倍数 int) map[rune][]string {
|
||||
m := make(map[rune][]string, len(表)*倍数)
|
||||
for _, lst := range 表 {
|
||||
for _, s := range lst {
|
||||
k := []rune(s)[0]
|
||||
m[k] = append(m[k], s)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// 低阶逆声母 rune声母到声母的逆映射
|
||||
var 低阶逆声母 = 低阶逆初始化(声母[:], 32)
|
||||
|
||||
func 逆初始化[T ~uint8](表 [][]string, 倍数 int) map[string]T {
|
||||
m := make(map[string]T, len(表)*倍数)
|
||||
for i, lst := range 表 {
|
||||
for _, s := range lst {
|
||||
m[s] = T(i)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// 逆声母 声母到枚举的逆映射
|
||||
var 逆声母 = 逆初始化[声母枚举](声母[:], 32)
|
||||
|
||||
type 韵母枚举 uint8
|
||||
|
||||
// String 国际音标
|
||||
@@ -150,6 +175,12 @@ var 韵母 = [...][]string{
|
||||
{string([]rune("🕸️")[0]), "🕸️"}, {"💡", "🪔"}, {"🦅"}, {"🐝"}, {"🌈"}, {"😳"}, // jiong 囧
|
||||
}
|
||||
|
||||
// 低阶逆韵母 rune韵母到韵母的逆映射
|
||||
var 低阶逆韵母 = 低阶逆初始化(韵母[:], 8)
|
||||
|
||||
// 逆韵母 韵母到枚举的逆映射
|
||||
var 逆韵母 = 逆初始化[韵母枚举](韵母[:], 8)
|
||||
|
||||
type 声调枚举 uint8
|
||||
|
||||
// String 返回传统调名
|
||||
@@ -169,6 +200,12 @@ const (
|
||||
|
||||
var 声调 = [...][]string{{"🍉"}, {"🧗", "🧗♀️", "🧗♂️", "🦎"}, {"🐴", "🐎"}, {"😨"}, {"😯"}}
|
||||
|
||||
// 低阶逆声调 rune声调到声调的逆映射
|
||||
var 低阶逆声调 = 低阶逆初始化(声调[:], 4)
|
||||
|
||||
// 逆声调 声调到枚举的逆映射
|
||||
var 逆声调 = 逆初始化[声调枚举](声调[:], 4)
|
||||
|
||||
// 校验表 用 校验表长度 个unicode控制字符做校验和验证此序列是由本程序生成而非手写的
|
||||
//
|
||||
// 具体做法是先对后面的文本做crc32然后取 校验表长度^校验字节数 的模
|
||||
@@ -208,3 +245,14 @@ var 逆校验表 = func() map[rune]uint8 {
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
// 逆部首后备 部首后备逆查表 一对多
|
||||
var 逆部首后备 = func() map[string][]rune {
|
||||
m := make(map[string][]rune, len(部首后备)*4)
|
||||
for r, e := range 部首后备 {
|
||||
if 无此字符(m[e], r) {
|
||||
m[e] = append(m[e], r)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
149
lookup.go
149
lookup.go
@@ -3,44 +3,35 @@ package emozi
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var 空 = "🈳️"
|
||||
|
||||
func (c *Coder) 查声母(s 声母枚举) string {
|
||||
lst := 声母[s]
|
||||
func 随机正查(m [][]string, isRandom bool, i uint8) string {
|
||||
lst := m[i]
|
||||
if len(lst) == 0 {
|
||||
return 空
|
||||
}
|
||||
if len(lst) == 1 || !c.isRandom {
|
||||
if len(lst) == 1 || !isRandom {
|
||||
return lst[0]
|
||||
}
|
||||
return lst[rand.Intn(len(lst))]
|
||||
}
|
||||
|
||||
func (c *Coder) 查韵母(y 韵母枚举) string {
|
||||
lst := 韵母[y]
|
||||
if len(lst) == 0 {
|
||||
return 空
|
||||
}
|
||||
if len(lst) == 1 || !c.isRandom {
|
||||
return lst[0]
|
||||
}
|
||||
return lst[rand.Intn(len(lst))]
|
||||
func (c *Coder) 声母(isRandom bool, s 声母枚举) string {
|
||||
return 随机正查(声母[:], isRandom, uint8(s))
|
||||
}
|
||||
|
||||
func (c *Coder) 查声调(t 声调枚举) string {
|
||||
lst := 声调[t]
|
||||
if len(lst) == 0 {
|
||||
return 空
|
||||
}
|
||||
if len(lst) == 1 || !c.isRandom {
|
||||
return lst[0]
|
||||
}
|
||||
return lst[rand.Intn(len(lst))]
|
||||
func (c *Coder) 韵母(isRandom bool, y 韵母枚举) string {
|
||||
return 随机正查(韵母[:], isRandom, uint8(y))
|
||||
}
|
||||
|
||||
func (c *Coder) 查部首(r rune) string {
|
||||
func (c *Coder) 声调(isRandom bool, t 声调枚举) string {
|
||||
return 随机正查(声调[:], isRandom, uint8(t))
|
||||
}
|
||||
|
||||
func (c *Coder) 部首(r rune) string {
|
||||
c.mu.RLock()
|
||||
e, ok := c.部首缓存[r]
|
||||
c.mu.RUnlock()
|
||||
@@ -62,3 +53,117 @@ func (c *Coder) 查部首(r rune) string {
|
||||
c.部首缓存[r] = 空
|
||||
return 空
|
||||
}
|
||||
|
||||
func 二阶逆查[E ~uint8](lowm map[rune][]string, m map[string]E, s string) (enum E, n int) {
|
||||
lowk := rune(0)
|
||||
lows := s
|
||||
if len(lows) > 12 {
|
||||
lows = lows[:12]
|
||||
}
|
||||
r := []rune(lows)
|
||||
if len(r) == 0 {
|
||||
return
|
||||
}
|
||||
lowk = r[0]
|
||||
ks := lowm[lowk]
|
||||
if len(ks) == 0 {
|
||||
return
|
||||
}
|
||||
// 寻找最长匹配 T
|
||||
matchp := -1
|
||||
matchl := 0
|
||||
for i, k := range ks {
|
||||
if strings.HasPrefix(s, k) {
|
||||
if len(k) > matchl {
|
||||
matchl = len(k)
|
||||
matchp = i
|
||||
}
|
||||
}
|
||||
}
|
||||
if matchp < 0 {
|
||||
return
|
||||
}
|
||||
enum, ok := m[ks[matchp]]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
n = matchl
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Coder) 逆声母(s string) (声母枚举, int) {
|
||||
return 二阶逆查[声母枚举](低阶逆声母, 逆声母, s)
|
||||
}
|
||||
|
||||
func (c *Coder) 逆韵母(s string) (韵母枚举, int) {
|
||||
return 二阶逆查[韵母枚举](低阶逆韵母, 逆韵母, s)
|
||||
}
|
||||
func (c *Coder) 逆声调(s string) (声调枚举, int) {
|
||||
return 二阶逆查[声调枚举](低阶逆声调, 逆声调, s)
|
||||
}
|
||||
|
||||
func (c *Coder) 逆部首(s string) (rs []rune, n int) {
|
||||
lim := len(s)
|
||||
if lim > 32 {
|
||||
lim = 32
|
||||
}
|
||||
c.mu.RLock()
|
||||
for i := 1; i < lim; i++ {
|
||||
l := c.逆部首缓存[s[:i]]
|
||||
if len(l) > 0 {
|
||||
rs = l
|
||||
n = i
|
||||
}
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
if n > 0 && len(rs) > 0 {
|
||||
return
|
||||
}
|
||||
x := &部首表{}
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString("WHERE ")
|
||||
for i := 1; i < lim; i++ {
|
||||
sb.WriteString("E='")
|
||||
sb.WriteString(s[:i])
|
||||
sb.WriteString("' OR ")
|
||||
}
|
||||
q := sb.String()[:sb.Len()-4]
|
||||
n = 0
|
||||
e := ""
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
err := c.db.FindFor(部首表名, x, q, func() error {
|
||||
if len(x.E) > n {
|
||||
n = len(x.E)
|
||||
rs = rs[:0]
|
||||
e = x.E
|
||||
}
|
||||
if len(x.E) == n && 无此字符(rs, x.R) {
|
||||
rs = append(rs, x.R)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err == nil && len(rs) > 0 && n > 0 {
|
||||
c.逆部首缓存[e] = rs
|
||||
return
|
||||
}
|
||||
for i := 1; i < lim; i++ {
|
||||
k := s[:i]
|
||||
innerrs, ok := 逆部首后备[k]
|
||||
c.逆部首缓存[k] = innerrs
|
||||
if ok && len(innerrs) > 0 {
|
||||
n = i
|
||||
rs = innerrs
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func 无此字符(runes []rune, ch rune) bool {
|
||||
for _, r := range runes {
|
||||
if ch == r {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
package emozi
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShengmuString(t *testing.T) {
|
||||
for i := 0; i < len(声母); i++ {
|
||||
t.Log(声母枚举(i).String())
|
||||
if 声母枚举(i).String() != strings.TrimSpace(声母枚举(i).String()) {
|
||||
t.Fatal("声母: '", 声母枚举(i), "'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitPinyin(t *testing.T) {
|
||||
s, y, tone, err := SplitPinyin("yōng")
|
||||
|
||||
@@ -29,7 +29,7 @@ func main() {
|
||||
panic(fmt.Sprintf("ERROR: creating gocc: %v", err))
|
||||
}
|
||||
_ = os.RemoveAll(emozi.EmoziDatabasePath)
|
||||
c, err := emozi.NewCoder(false, time.Minute)
|
||||
c, err := emozi.NewCoder(time.Minute)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("ERROR: creating emozi coder: %v", err))
|
||||
}
|
||||
|
||||
920
radical.go
920
radical.go
@@ -40,508 +40,508 @@ var 部首后备 = map[rune]string{
|
||||
'辵': "🚶",
|
||||
'彳': "🚦",
|
||||
'廴': "🚥",
|
||||
'㢟': "🈳️",
|
||||
'㢟': 空,
|
||||
'行': "⛕",
|
||||
'齒': "🈳️",
|
||||
'牙': "🈳️",
|
||||
'足': "🈳️",
|
||||
'疋': "🈳️",
|
||||
'品': "🈳️",
|
||||
'龠': "🈳️",
|
||||
'冊': "🈳️",
|
||||
'㗊': "🈳️",
|
||||
'齒': 空,
|
||||
'牙': 空,
|
||||
'足': 空,
|
||||
'疋': 空,
|
||||
'品': 空,
|
||||
'龠': 空,
|
||||
'冊': 空,
|
||||
'㗊': 空,
|
||||
'舌': "👅",
|
||||
'干': "🈳️",
|
||||
'𧮫': "🈳️",
|
||||
'只': "🈳️",
|
||||
'㕯': "🈳️",
|
||||
'句': "🈳️",
|
||||
'丩': "🈳️",
|
||||
'干': 空,
|
||||
'𧮫': 空,
|
||||
'只': 空,
|
||||
'㕯': 空,
|
||||
'句': 空,
|
||||
'丩': 空,
|
||||
'古': "🏺",
|
||||
'十': "🔟",
|
||||
'卅': "🌍",
|
||||
'言': "💬",
|
||||
'田': "👨🌾",
|
||||
'誩': "🈳️",
|
||||
'誩': 空,
|
||||
'音': "🎵",
|
||||
'䇂': "🈳️",
|
||||
'丵': "🈳️",
|
||||
'菐': "🈳️",
|
||||
'𠬞': "🈳️",
|
||||
'𠬜': "🈳️",
|
||||
'共': "🈳️",
|
||||
'異': "🈳️",
|
||||
'舁': "🈳️",
|
||||
'𦥑': "🈳️",
|
||||
'䢅': "🈳️",
|
||||
'爨': "🈳️",
|
||||
'革': "🈳️",
|
||||
'鬲': "🈳️",
|
||||
'䰜': "🈳️",
|
||||
'䇂': 空,
|
||||
'丵': 空,
|
||||
'菐': 空,
|
||||
'𠬞': 空,
|
||||
'𠬜': 空,
|
||||
'共': 空,
|
||||
'異': 空,
|
||||
'舁': 空,
|
||||
'𦥑': 空,
|
||||
'䢅': 空,
|
||||
'爨': 空,
|
||||
'革': 空,
|
||||
'鬲': 空,
|
||||
'䰜': 空,
|
||||
'爪': "🤏",
|
||||
'丮': "🈳️",
|
||||
'丮': 空,
|
||||
'鬥': "👊",
|
||||
'又': "🈳️",
|
||||
'𠂇': "🈳️",
|
||||
'史': "🈳️",
|
||||
'支': "🈳️",
|
||||
'𦘒': "🈳️",
|
||||
'又': 空,
|
||||
'𠂇': 空,
|
||||
'史': 空,
|
||||
'支': 空,
|
||||
'𦘒': 空,
|
||||
'聿': "✍",
|
||||
'畫': "🎨",
|
||||
'隶': "🈳️",
|
||||
'臤': "🈳️",
|
||||
'臣': "🈳️",
|
||||
'殳': "🈳️",
|
||||
'隶': 空,
|
||||
'臤': 空,
|
||||
'臣': 空,
|
||||
'殳': 空,
|
||||
'殺': "🪚",
|
||||
'𠘧': "🈳️",
|
||||
'寸': "🈳️",
|
||||
'皮': "🈳️",
|
||||
'㼱': "🈳️",
|
||||
'攴': "🈳️",
|
||||
'𠘧': 空,
|
||||
'寸': 空,
|
||||
'皮': 空,
|
||||
'㼱': 空,
|
||||
'攴': 空,
|
||||
'女': "👩",
|
||||
'教': "🈳️",
|
||||
'教': 空,
|
||||
'卜': "🔮",
|
||||
'用': "🈳️",
|
||||
'爻': "🈳️",
|
||||
'㸚': "🈳️",
|
||||
'𡕥': "🈳️",
|
||||
'用': 空,
|
||||
'爻': 空,
|
||||
'㸚': 空,
|
||||
'𡕥': 空,
|
||||
'目': "👁️",
|
||||
'䀠': "👀",
|
||||
'眉': "🤨",
|
||||
'盾': "🈳️",
|
||||
'盾': 空,
|
||||
'自': "👃",
|
||||
'𪞶': "🈳️",
|
||||
'𪞶': 空,
|
||||
'鼻': "👃",
|
||||
'皕': "🈳️",
|
||||
'習': "🈳️",
|
||||
'皕': 空,
|
||||
'習': 空,
|
||||
'羽': "🪶",
|
||||
'隹': "🐦",
|
||||
'奞': "🈳️",
|
||||
'雈': "🈳️",
|
||||
'𦫳': "🈳️",
|
||||
'𥄕': "🈳️",
|
||||
'奞': 空,
|
||||
'雈': 空,
|
||||
'𦫳': 空,
|
||||
'𥄕': 空,
|
||||
'羊': "🐑",
|
||||
'羴': "🈳️",
|
||||
'瞿': "🈳️",
|
||||
'雔': "🈳️",
|
||||
'雥': "🈳️",
|
||||
'羴': 空,
|
||||
'瞿': 空,
|
||||
'雔': 空,
|
||||
'雥': 空,
|
||||
'鳥': "🦢",
|
||||
'烏': "🐦⬛",
|
||||
'𠦒': "🈳",
|
||||
'冓': "🈳️",
|
||||
'幺': "🈳️",
|
||||
'𢆶': "🈳️",
|
||||
'叀': "🈳️",
|
||||
'玄': "🈳️",
|
||||
'予': "🈳️",
|
||||
'放': "🈳️",
|
||||
'𠬪': "🈳️",
|
||||
'𣦼': "🈳️",
|
||||
'歺': "🈳️",
|
||||
'死': "🈳️",
|
||||
'冎': "🈳️",
|
||||
'骨': "🈳️",
|
||||
'肉': "🈳️",
|
||||
'筋': "🈳️",
|
||||
'𠦒': 空,
|
||||
'冓': 空,
|
||||
'幺': 空,
|
||||
'𢆶': 空,
|
||||
'叀': 空,
|
||||
'玄': 空,
|
||||
'予': 空,
|
||||
'放': 空,
|
||||
'𠬪': 空,
|
||||
'𣦼': 空,
|
||||
'歺': 空,
|
||||
'死': 空,
|
||||
'冎': 空,
|
||||
'骨': 空,
|
||||
'肉': 空,
|
||||
'筋': 空,
|
||||
'刀': "🔪",
|
||||
'刃': "🔪",
|
||||
'㓞': "🈳️",
|
||||
'丯': "🈳️",
|
||||
'耒': "🈳️",
|
||||
'㓞': 空,
|
||||
'丯': 空,
|
||||
'耒': 空,
|
||||
'角': "🥐",
|
||||
'竹': "🎋",
|
||||
'箕': "🈳️",
|
||||
'丌': "🈳️",
|
||||
'箕': 空,
|
||||
'丌': 空,
|
||||
'左': "👈",
|
||||
'工': "🈳️",
|
||||
'㠭': "🈳️",
|
||||
'巫': "🈳️",
|
||||
'甘': "🈳️",
|
||||
'曰': "🈳️",
|
||||
'乃': "🈳️",
|
||||
'丂': "🈳️",
|
||||
'可': "🈳️",
|
||||
'兮': "🈳️",
|
||||
'号': "🈳️",
|
||||
'亏': "🈳️",
|
||||
'旨': "🈳️",
|
||||
'喜': "🈳️",
|
||||
'壴': "🈳️",
|
||||
'鼓': "🈳️",
|
||||
'豈': "🈳️",
|
||||
'豆': "🈳️",
|
||||
'豊': "🈳️",
|
||||
'豐': "🈳️",
|
||||
'䖒': "🈳️",
|
||||
'虍': "🈳️",
|
||||
'虎': "🈳️",
|
||||
'虤': "🈳️",
|
||||
'皿': "🈳️",
|
||||
'𠙴': "🈳️",
|
||||
'去': "🈳️",
|
||||
'血': "🈳️",
|
||||
'丶': "🈳️",
|
||||
'丹': "🈳️",
|
||||
'青': "🈳️",
|
||||
'井': "🈳️",
|
||||
'皀': "🈳️",
|
||||
'鬯': "🈳️",
|
||||
'食': "🈳️",
|
||||
'亼': "🈳️",
|
||||
'會': "🈳️",
|
||||
'倉': "🈳️",
|
||||
'入': "🈳️",
|
||||
'缶': "🈳️",
|
||||
'矢': "🈳️",
|
||||
'高': "🈳️",
|
||||
'冂': "🈳️",
|
||||
'𩫖': "🈳️",
|
||||
'京': "🈳️",
|
||||
'亯': "🈳️",
|
||||
'㫗': "🈳️",
|
||||
'畗': "🈳️",
|
||||
'㐭': "🈳️",
|
||||
'嗇': "🈳️",
|
||||
'來': "🈳️",
|
||||
'麥': "🈳️",
|
||||
'夊': "🈳️",
|
||||
'舛': "🈳️",
|
||||
'舜': "🈳️",
|
||||
'韋': "🈳️",
|
||||
'弟': "🈳️",
|
||||
'夂': "🈳️",
|
||||
'久': "🈳️",
|
||||
'桀': "🈳️",
|
||||
'木': "🈳️",
|
||||
'東': "🈳️",
|
||||
'林': "🈳️",
|
||||
'才': "🈳️",
|
||||
'叒': "🈳️",
|
||||
'之': "🈳️",
|
||||
'帀': "🈳️",
|
||||
'出': "🈳️",
|
||||
'𣎵': "🈳️",
|
||||
'生': "🈳️",
|
||||
'乇': "🈳️",
|
||||
'𠂹': "🈳️",
|
||||
'𠌶': "🈳️",
|
||||
'華': "🈳️",
|
||||
'𥝌': "🈳️",
|
||||
'稽': "🈳️",
|
||||
'巢': "🈳️",
|
||||
'桼': "🈳️",
|
||||
'束': "🈳️",
|
||||
'㯻': "🈳️",
|
||||
'囗': "🈳️",
|
||||
'員': "🈳️",
|
||||
'貝': "🈳️",
|
||||
'邑': "🈳️",
|
||||
'𨛜': "🈳️",
|
||||
'日': "🈳️",
|
||||
'旦': "🈳️",
|
||||
'倝': "🈳️",
|
||||
'㫃': "🈳️",
|
||||
'冥': "🈳️",
|
||||
'晶': "🈳️",
|
||||
'月': "🈳️",
|
||||
'有': "🈳️",
|
||||
'朙': "🈳️",
|
||||
'囧': "🈳️",
|
||||
'工': 空,
|
||||
'㠭': 空,
|
||||
'巫': 空,
|
||||
'甘': 空,
|
||||
'曰': 空,
|
||||
'乃': 空,
|
||||
'丂': 空,
|
||||
'可': 空,
|
||||
'兮': 空,
|
||||
'号': 空,
|
||||
'亏': 空,
|
||||
'旨': 空,
|
||||
'喜': 空,
|
||||
'壴': 空,
|
||||
'鼓': 空,
|
||||
'豈': 空,
|
||||
'豆': 空,
|
||||
'豊': 空,
|
||||
'豐': 空,
|
||||
'䖒': 空,
|
||||
'虍': 空,
|
||||
'虎': 空,
|
||||
'虤': 空,
|
||||
'皿': 空,
|
||||
'𠙴': 空,
|
||||
'去': 空,
|
||||
'血': 空,
|
||||
'丶': 空,
|
||||
'丹': 空,
|
||||
'青': 空,
|
||||
'井': 空,
|
||||
'皀': 空,
|
||||
'鬯': 空,
|
||||
'食': 空,
|
||||
'亼': 空,
|
||||
'會': 空,
|
||||
'倉': 空,
|
||||
'入': 空,
|
||||
'缶': 空,
|
||||
'矢': 空,
|
||||
'高': 空,
|
||||
'冂': 空,
|
||||
'𩫖': 空,
|
||||
'京': 空,
|
||||
'亯': 空,
|
||||
'㫗': 空,
|
||||
'畗': 空,
|
||||
'㐭': 空,
|
||||
'嗇': 空,
|
||||
'來': 空,
|
||||
'麥': 空,
|
||||
'夊': 空,
|
||||
'舛': 空,
|
||||
'舜': 空,
|
||||
'韋': 空,
|
||||
'弟': 空,
|
||||
'夂': 空,
|
||||
'久': 空,
|
||||
'桀': 空,
|
||||
'木': 空,
|
||||
'東': 空,
|
||||
'林': 空,
|
||||
'才': 空,
|
||||
'叒': 空,
|
||||
'之': 空,
|
||||
'帀': 空,
|
||||
'出': 空,
|
||||
'𣎵': 空,
|
||||
'生': 空,
|
||||
'乇': 空,
|
||||
'𠂹': 空,
|
||||
'𠌶': 空,
|
||||
'華': 空,
|
||||
'𥝌': 空,
|
||||
'稽': 空,
|
||||
'巢': 空,
|
||||
'桼': 空,
|
||||
'束': 空,
|
||||
'㯻': 空,
|
||||
'囗': 空,
|
||||
'員': 空,
|
||||
'貝': 空,
|
||||
'邑': 空,
|
||||
'𨛜': 空,
|
||||
'日': 空,
|
||||
'旦': 空,
|
||||
'倝': 空,
|
||||
'㫃': 空,
|
||||
'冥': 空,
|
||||
'晶': 空,
|
||||
'月': 空,
|
||||
'有': 空,
|
||||
'朙': 空,
|
||||
'囧': 空,
|
||||
'夕': "🌇",
|
||||
'多': "🪩",
|
||||
'毌': "🈳️",
|
||||
'𢎘': "🈳️",
|
||||
'𣐺': "🈳️",
|
||||
'𠧪': "🈳️",
|
||||
'齊': "🈳️",
|
||||
'朿': "🈳️",
|
||||
'片': "🈳️",
|
||||
'鼎': "🈳️",
|
||||
'克': "🈳️",
|
||||
'彔': "🈳️",
|
||||
'禾': "🈳️",
|
||||
'秝': "🈳️",
|
||||
'黍': "🈳️",
|
||||
'香': "🈳️",
|
||||
'米': "🈳️",
|
||||
'毇': "🈳️",
|
||||
'臼': "🈳️",
|
||||
'凶': "🈳️",
|
||||
'朩': "🈳️",
|
||||
'𣏟': "🈳️",
|
||||
'麻': "🈳️",
|
||||
'尗': "🈳️",
|
||||
'耑': "🈳️",
|
||||
'韭': "🈳️",
|
||||
'瓜': "🈳️",
|
||||
'瓠': "🈳️",
|
||||
'毌': 空,
|
||||
'𢎘': 空,
|
||||
'𣐺': 空,
|
||||
'𠧪': 空,
|
||||
'齊': 空,
|
||||
'朿': 空,
|
||||
'片': 空,
|
||||
'鼎': 空,
|
||||
'克': 空,
|
||||
'彔': 空,
|
||||
'禾': 空,
|
||||
'秝': 空,
|
||||
'黍': 空,
|
||||
'香': 空,
|
||||
'米': 空,
|
||||
'毇': 空,
|
||||
'臼': 空,
|
||||
'凶': 空,
|
||||
'朩': 空,
|
||||
'𣏟': 空,
|
||||
'麻': 空,
|
||||
'尗': 空,
|
||||
'耑': 空,
|
||||
'韭': 空,
|
||||
'瓜': 空,
|
||||
'瓠': 空,
|
||||
'宀': "🏠",
|
||||
'宮': "🏛",
|
||||
'呂': "🩻",
|
||||
'穴': "🕳️",
|
||||
'㝱': "🈳️",
|
||||
'㝱': 空,
|
||||
'疒': "😷",
|
||||
'冖': "🗃",
|
||||
'𠔼': "🈳️",
|
||||
'冃': "🈳️",
|
||||
'㒳': "🈳️",
|
||||
'网': "🈳️",
|
||||
'襾': "🈳️",
|
||||
'𠔼': 空,
|
||||
'冃': 空,
|
||||
'㒳': 空,
|
||||
'网': 空,
|
||||
'襾': 空,
|
||||
'巾': "🧣",
|
||||
'巿': "🈳️",
|
||||
'帛': "🈳️",
|
||||
'巿': 空,
|
||||
'帛': 空,
|
||||
'白': "⚪",
|
||||
'㡀': "🈳️",
|
||||
'黹': "🈳️",
|
||||
'𠤎': "🈳️",
|
||||
'匕': "🈳️",
|
||||
'从': "🈳️",
|
||||
'比': "🈳️",
|
||||
'北': "🈳️",
|
||||
'丘': "🈳️",
|
||||
'㐺': "🈳️",
|
||||
'𡈼': "🈳️",
|
||||
'重': "🈳️",
|
||||
'臥': "🈳️",
|
||||
'身': "🈳️",
|
||||
'㐆': "🈳️",
|
||||
'衣': "🈳️",
|
||||
'裘': "🈳️",
|
||||
'老': "🈳️",
|
||||
'毛': "🈳️",
|
||||
'毳': "🈳️",
|
||||
'尸': "🈳️",
|
||||
'尺': "🈳️",
|
||||
'尾': "🈳️",
|
||||
'履': "🈳️",
|
||||
'㡀': 空,
|
||||
'黹': 空,
|
||||
'𠤎': 空,
|
||||
'匕': 空,
|
||||
'从': 空,
|
||||
'比': 空,
|
||||
'北': 空,
|
||||
'丘': 空,
|
||||
'㐺': 空,
|
||||
'𡈼': 空,
|
||||
'重': 空,
|
||||
'臥': 空,
|
||||
'身': 空,
|
||||
'㐆': 空,
|
||||
'衣': 空,
|
||||
'裘': 空,
|
||||
'老': 空,
|
||||
'毛': 空,
|
||||
'毳': 空,
|
||||
'尸': 空,
|
||||
'尺': 空,
|
||||
'尾': 空,
|
||||
'履': 空,
|
||||
'舟': "🛶",
|
||||
'方': "🈳️",
|
||||
'儿': "🈳️",
|
||||
'兄': "🈳️",
|
||||
'兂': "🈳️",
|
||||
'皃': "🈳️",
|
||||
'𠑹': "🈳️",
|
||||
'先': "🈳️",
|
||||
'禿': "🈳️",
|
||||
'見': "🈳️",
|
||||
'覞': "🈳️",
|
||||
'欠': "🈳️",
|
||||
'㱃': "🈳️",
|
||||
'㳄': "🈳️",
|
||||
'旡': "🈳️",
|
||||
'頁': "🈳️",
|
||||
'𦣻': "🈳️",
|
||||
'面': "🈳️",
|
||||
'丏': "🈳️",
|
||||
'首': "🈳️",
|
||||
'𥄉': "🈳️",
|
||||
'須': "🈳️",
|
||||
'彡': "🈳️",
|
||||
'彣': "🈳️",
|
||||
'文': "🈳️",
|
||||
'髟': "🈳️",
|
||||
'后': "🈳️",
|
||||
'司': "🈳️",
|
||||
'卮': "🈳️",
|
||||
'卩': "🈳️",
|
||||
'印': "🈳️",
|
||||
'色': "🈳️",
|
||||
'𠨍': "🈳️",
|
||||
'辟': "🈳️",
|
||||
'勹': "🈳️",
|
||||
'包': "🈳️",
|
||||
'茍': "🈳️",
|
||||
'鬼': "🈳️",
|
||||
'甶': "🈳️",
|
||||
'厶': "🈳️",
|
||||
'嵬': "🈳️",
|
||||
'山': "🈳️",
|
||||
'屾': "🈳️",
|
||||
'屵': "🈳️",
|
||||
'广': "🈳️",
|
||||
'厂': "🈳️",
|
||||
'丸': "🈳️",
|
||||
'危': "🈳️",
|
||||
'石': "🈳️",
|
||||
'長': "🈳️",
|
||||
'勿': "🈳️",
|
||||
'冄': "🈳️",
|
||||
'而': "🈳️",
|
||||
'豕': "🈳️",
|
||||
'㣇': "🈳️",
|
||||
'彑': "🈳️",
|
||||
'豚': "🈳️",
|
||||
'豸': "🈳️",
|
||||
'𤉡': "🈳️",
|
||||
'易': "🈳️",
|
||||
'象': "🈳️",
|
||||
'馬': "🈳️",
|
||||
'𢊁': "🈳️",
|
||||
'鹿': "🈳️",
|
||||
'麤': "🈳️",
|
||||
'㲋': "🈳️",
|
||||
'兔': "🈳️",
|
||||
'萈': "🈳️",
|
||||
'犬': "🈳️",
|
||||
'㹜': "🈳️",
|
||||
'鼠': "🈳️",
|
||||
'能': "🈳️",
|
||||
'熊': "🈳️",
|
||||
'火': "🈳️",
|
||||
'炎': "🈳️",
|
||||
'黑': "🈳️",
|
||||
'囪': "🈳️",
|
||||
'焱': "🈳️",
|
||||
'炙': "🈳️",
|
||||
'赤': "🈳️",
|
||||
'大': "🈳️",
|
||||
'亦': "🈳️",
|
||||
'夨': "🈳️",
|
||||
'夭': "🈳️",
|
||||
'交': "🈳️",
|
||||
'尣': "🈳️",
|
||||
'壺': "🈳️",
|
||||
'壹': "🈳️",
|
||||
'㚔': "🈳️",
|
||||
'奢': "🈳️",
|
||||
'亢': "🈳️",
|
||||
'夲': "🈳️",
|
||||
'夰': "🈳️",
|
||||
'亣': "🈳️",
|
||||
'夫': "🈳️",
|
||||
'立': "🈳️",
|
||||
'竝': "🈳️",
|
||||
'囟': "🈳️",
|
||||
'思': "🈳️",
|
||||
'心': "🈳️",
|
||||
'惢': "🈳️",
|
||||
'水': "🈳️",
|
||||
'沝': "🈳️",
|
||||
'瀕': "🈳️",
|
||||
'𡿨': "🈳️",
|
||||
'巜': "🈳️",
|
||||
'川': "🈳️",
|
||||
'泉': "🈳️",
|
||||
'灥': "🈳️",
|
||||
'永': "🈳️",
|
||||
'𠂢': "🈳️",
|
||||
'谷': "🈳️",
|
||||
'仌': "🈳️",
|
||||
'雨': "🈳️",
|
||||
'雲': "🈳️",
|
||||
'魚': "🈳️",
|
||||
'𩺰': "🈳️",
|
||||
'燕': "🈳️",
|
||||
'龍': "🈳️",
|
||||
'飛': "🈳️",
|
||||
'非': "🈳️",
|
||||
'卂': "🈳️",
|
||||
'𠃉': "🈳️",
|
||||
'不': "🈳️",
|
||||
'至': "🈳️",
|
||||
'西': "🈳️",
|
||||
'鹵': "🈳️",
|
||||
'鹽': "🈳️",
|
||||
'戶': "🈳️",
|
||||
'門': "🈳️",
|
||||
'耳': "🈳️",
|
||||
'𦣞': "🈳️",
|
||||
'方': 空,
|
||||
'儿': 空,
|
||||
'兄': 空,
|
||||
'兂': 空,
|
||||
'皃': 空,
|
||||
'𠑹': 空,
|
||||
'先': 空,
|
||||
'禿': 空,
|
||||
'見': 空,
|
||||
'覞': 空,
|
||||
'欠': 空,
|
||||
'㱃': 空,
|
||||
'㳄': 空,
|
||||
'旡': 空,
|
||||
'頁': 空,
|
||||
'𦣻': 空,
|
||||
'面': 空,
|
||||
'丏': 空,
|
||||
'首': 空,
|
||||
'𥄉': 空,
|
||||
'須': 空,
|
||||
'彡': 空,
|
||||
'彣': 空,
|
||||
'文': 空,
|
||||
'髟': 空,
|
||||
'后': 空,
|
||||
'司': 空,
|
||||
'卮': 空,
|
||||
'卩': 空,
|
||||
'印': 空,
|
||||
'色': 空,
|
||||
'𠨍': 空,
|
||||
'辟': 空,
|
||||
'勹': 空,
|
||||
'包': 空,
|
||||
'茍': 空,
|
||||
'鬼': 空,
|
||||
'甶': 空,
|
||||
'厶': 空,
|
||||
'嵬': 空,
|
||||
'山': 空,
|
||||
'屾': 空,
|
||||
'屵': 空,
|
||||
'广': 空,
|
||||
'厂': 空,
|
||||
'丸': 空,
|
||||
'危': 空,
|
||||
'石': 空,
|
||||
'長': 空,
|
||||
'勿': 空,
|
||||
'冄': 空,
|
||||
'而': 空,
|
||||
'豕': 空,
|
||||
'㣇': 空,
|
||||
'彑': 空,
|
||||
'豚': 空,
|
||||
'豸': 空,
|
||||
'𤉡': 空,
|
||||
'易': 空,
|
||||
'象': 空,
|
||||
'馬': 空,
|
||||
'𢊁': 空,
|
||||
'鹿': 空,
|
||||
'麤': 空,
|
||||
'㲋': 空,
|
||||
'兔': 空,
|
||||
'萈': 空,
|
||||
'犬': 空,
|
||||
'㹜': 空,
|
||||
'鼠': 空,
|
||||
'能': 空,
|
||||
'熊': 空,
|
||||
'火': 空,
|
||||
'炎': 空,
|
||||
'黑': 空,
|
||||
'囪': 空,
|
||||
'焱': 空,
|
||||
'炙': 空,
|
||||
'赤': 空,
|
||||
'大': 空,
|
||||
'亦': 空,
|
||||
'夨': 空,
|
||||
'夭': 空,
|
||||
'交': 空,
|
||||
'尣': 空,
|
||||
'壺': 空,
|
||||
'壹': 空,
|
||||
'㚔': 空,
|
||||
'奢': 空,
|
||||
'亢': 空,
|
||||
'夲': 空,
|
||||
'夰': 空,
|
||||
'亣': 空,
|
||||
'夫': 空,
|
||||
'立': 空,
|
||||
'竝': 空,
|
||||
'囟': 空,
|
||||
'思': 空,
|
||||
'心': 空,
|
||||
'惢': 空,
|
||||
'水': 空,
|
||||
'沝': 空,
|
||||
'瀕': 空,
|
||||
'𡿨': 空,
|
||||
'巜': 空,
|
||||
'川': 空,
|
||||
'泉': 空,
|
||||
'灥': 空,
|
||||
'永': 空,
|
||||
'𠂢': 空,
|
||||
'谷': 空,
|
||||
'仌': 空,
|
||||
'雨': 空,
|
||||
'雲': 空,
|
||||
'魚': 空,
|
||||
'𩺰': 空,
|
||||
'燕': 空,
|
||||
'龍': 空,
|
||||
'飛': 空,
|
||||
'非': 空,
|
||||
'卂': 空,
|
||||
'𠃉': 空,
|
||||
'不': 空,
|
||||
'至': 空,
|
||||
'西': 空,
|
||||
'鹵': 空,
|
||||
'鹽': 空,
|
||||
'戶': 空,
|
||||
'門': 空,
|
||||
'耳': 空,
|
||||
'𦣞': 空,
|
||||
'手': "✋",
|
||||
'𠦬': "🈳️",
|
||||
'毋': "🈳️",
|
||||
'民': "🈳️",
|
||||
'丿': "🈳️",
|
||||
'𠂆': "🈳️",
|
||||
'乁': "🈳️",
|
||||
'氏': "🈳️",
|
||||
'氐': "🈳️",
|
||||
'戈': "🈳️",
|
||||
'戉': "🈳️",
|
||||
'我': "🈳️",
|
||||
'亅': "🈳️",
|
||||
'珡': "🈳️",
|
||||
'𠃊': "🈳️",
|
||||
'亾': "🈳️",
|
||||
'匸': "🈳️",
|
||||
'匚': "🈳️",
|
||||
'曲': "🈳️",
|
||||
'甾': "🈳️",
|
||||
'瓦': "🈳️",
|
||||
'弓': "🈳️",
|
||||
'弜': "🈳️",
|
||||
'弦': "🈳️",
|
||||
'系': "🈳️",
|
||||
'糸': "🈳️",
|
||||
'素': "🈳️",
|
||||
'絲': "🈳️",
|
||||
'率': "🈳️",
|
||||
'虫': "🈳️",
|
||||
'䖵': "🈳️",
|
||||
'蟲': "🈳️",
|
||||
'風': "🈳️",
|
||||
'它': "🈳️",
|
||||
'龜': "🈳️",
|
||||
'黽': "🈳️",
|
||||
'卵': "🈳️",
|
||||
'二': "🈳️",
|
||||
'土': "🈳️",
|
||||
'垚': "🈳️",
|
||||
'堇': "🈳️",
|
||||
'里': "🈳️",
|
||||
'畕': "🈳️",
|
||||
'黃': "🈳️",
|
||||
'男': "🈳️",
|
||||
'力': "🈳️",
|
||||
'劦': "🈳️",
|
||||
'𠦬': 空,
|
||||
'毋': 空,
|
||||
'民': 空,
|
||||
'丿': 空,
|
||||
'𠂆': 空,
|
||||
'乁': 空,
|
||||
'氏': 空,
|
||||
'氐': 空,
|
||||
'戈': 空,
|
||||
'戉': 空,
|
||||
'我': 空,
|
||||
'亅': 空,
|
||||
'珡': 空,
|
||||
'𠃊': 空,
|
||||
'亾': 空,
|
||||
'匸': 空,
|
||||
'匚': 空,
|
||||
'曲': 空,
|
||||
'甾': 空,
|
||||
'瓦': 空,
|
||||
'弓': 空,
|
||||
'弜': 空,
|
||||
'弦': 空,
|
||||
'系': 空,
|
||||
'糸': 空,
|
||||
'素': 空,
|
||||
'絲': 空,
|
||||
'率': 空,
|
||||
'虫': 空,
|
||||
'䖵': 空,
|
||||
'蟲': 空,
|
||||
'風': 空,
|
||||
'它': 空,
|
||||
'龜': 空,
|
||||
'黽': 空,
|
||||
'卵': 空,
|
||||
'二': 空,
|
||||
'土': 空,
|
||||
'垚': 空,
|
||||
'堇': 空,
|
||||
'里': 空,
|
||||
'畕': 空,
|
||||
'黃': 空,
|
||||
'男': 空,
|
||||
'力': 空,
|
||||
'劦': 空,
|
||||
'金': "💰",
|
||||
'幵': "🈳️",
|
||||
'勺': "🈳️",
|
||||
'几': "🈳️",
|
||||
'且': "🈳️",
|
||||
'斤': "🈳️",
|
||||
'斗': "🈳️",
|
||||
'矛': "🈳️",
|
||||
'車': "🈳️",
|
||||
'𠂤': "🈳️",
|
||||
'𨸏': "🈳️",
|
||||
'𨺅': "🈳️",
|
||||
'厽': "🈳️",
|
||||
'四': "🈳️",
|
||||
'宁': "🈳️",
|
||||
'叕': "🈳️",
|
||||
'亞': "🈳️",
|
||||
'五': "🈳️",
|
||||
'六': "🈳️",
|
||||
'七': "🈳️",
|
||||
'九': "🈳️",
|
||||
'禸': "🈳️",
|
||||
'嘼': "🈳️",
|
||||
'甲': "🈳️",
|
||||
'乙': "🈳️",
|
||||
'丙': "🈳️",
|
||||
'丁': "🈳️",
|
||||
'戊': "🈳️",
|
||||
'己': "🈳️",
|
||||
'巴': "🈳️",
|
||||
'庚': "🈳️",
|
||||
'辛': "🈳️",
|
||||
'辡': "🈳️",
|
||||
'壬': "🈳️",
|
||||
'癸': "🈳️",
|
||||
'幵': 空,
|
||||
'勺': 空,
|
||||
'几': 空,
|
||||
'且': 空,
|
||||
'斤': 空,
|
||||
'斗': 空,
|
||||
'矛': 空,
|
||||
'車': 空,
|
||||
'𠂤': 空,
|
||||
'𨸏': 空,
|
||||
'𨺅': 空,
|
||||
'厽': 空,
|
||||
'四': 空,
|
||||
'宁': 空,
|
||||
'叕': 空,
|
||||
'亞': 空,
|
||||
'五': 空,
|
||||
'六': 空,
|
||||
'七': 空,
|
||||
'九': 空,
|
||||
'禸': 空,
|
||||
'嘼': 空,
|
||||
'甲': 空,
|
||||
'乙': 空,
|
||||
'丙': 空,
|
||||
'丁': 空,
|
||||
'戊': 空,
|
||||
'己': 空,
|
||||
'巴': 空,
|
||||
'庚': 空,
|
||||
'辛': 空,
|
||||
'辡': 空,
|
||||
'壬': 空,
|
||||
'癸': 空,
|
||||
'子': "🚼",
|
||||
'了': "🈳️",
|
||||
'孨': "🈳️",
|
||||
'𠫓': "🈳️",
|
||||
'丑': "🈳️",
|
||||
'寅': "🈳️",
|
||||
'戼': "🈳️",
|
||||
'辰': "🈳️",
|
||||
'巳': "🈳️",
|
||||
'午': "🈳️",
|
||||
'未': "🈳️",
|
||||
'申': "🈳️",
|
||||
'酉': "🈳️",
|
||||
'酋': "🈳️",
|
||||
'戌': "🈳️",
|
||||
'亥': "🈳️",
|
||||
'了': 空,
|
||||
'孨': 空,
|
||||
'𠫓': 空,
|
||||
'丑': 空,
|
||||
'寅': 空,
|
||||
'戼': 空,
|
||||
'辰': 空,
|
||||
'巳': 空,
|
||||
'午': 空,
|
||||
'未': 空,
|
||||
'申': 空,
|
||||
'酉': 空,
|
||||
'酋': 空,
|
||||
'戌': 空,
|
||||
'亥': 空,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package emozi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"hash/crc32"
|
||||
"strings"
|
||||
|
||||
base14 "github.com/fumiama/go-base16384"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidEmoziString = errors.New("invalid EmoziString")
|
||||
)
|
||||
|
||||
// EmoziString 一个颜文字汉字转写串, 包含串头 校验字节数*2 字节校验和
|
||||
type EmoziString string
|
||||
|
||||
@@ -35,7 +40,7 @@ func WrapRawEmoziString(s string) EmoziString {
|
||||
// String 输出不包含串头的转写串
|
||||
func (es EmoziString) String() string {
|
||||
if !es.IsValid() {
|
||||
return "ERROR: invalid EmoziString"
|
||||
return ErrInvalidEmoziString.Error()
|
||||
}
|
||||
rs := []rune(es)
|
||||
sb := strings.Builder{}
|
||||
|
||||
Reference in New Issue
Block a user