From ceb7686da6129bacda337e6be8391ea853062911 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?=
<41315874+fumiama@users.noreply.github.com>
Date: Wed, 14 Feb 2024 18:39:07 +0900
Subject: [PATCH] init
---
.gitignore | 6 +
README.md | 21 ++
codegen/radical/main.go | 54 ++++
coder.go | 178 +++++++++++++
coder_test.go | 29 +++
data.go | 38 +++
define.go | 210 +++++++++++++++
define_test.go | 22 ++
go.mod | 29 +++
go.sum | 43 ++++
lookup.go | 53 ++++
pinyin.go | 336 ++++++++++++++++++++++++
pinyin_test.go | 46 ++++
preprocess/main.go | 81 ++++++
radical.go | 547 ++++++++++++++++++++++++++++++++++++++++
string.go | 63 +++++
string_test.go | 20 ++
字.db | Bin 0 -> 671744 bytes
18 files changed, 1776 insertions(+)
create mode 100644 README.md
create mode 100644 codegen/radical/main.go
create mode 100644 coder.go
create mode 100644 coder_test.go
create mode 100644 data.go
create mode 100644 define.go
create mode 100644 define_test.go
create mode 100644 go.mod
create mode 100644 go.sum
create mode 100644 lookup.go
create mode 100644 pinyin.go
create mode 100644 pinyin_test.go
create mode 100644 preprocess/main.go
create mode 100644 radical.go
create mode 100644 string.go
create mode 100644 string_test.go
create mode 100644 字.db
diff --git a/.gitignore b/.gitignore
index 3b735ec..627108c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,9 @@
# Go workspace file
go.work
+
+# MacOS
+.DS_Store
+
+# json folder
+/data
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..537759a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+
+
+
EMOZI
+参考古埃及圣书体设计的一种基于颜文字的汉字抽象转写法
🐑🚬🧗👤🕸️😐🧗✍️👈🌞😨🏠🌹🧦😨👥🌹🔐😨💦⬅️☀️😨🏡💦💡🍉🌱🍵💡🧗🪓🍆👔😨🐶
+
+

+
+
+
+W.I.P.
+
+## 实用工具
+### 拼音识别拆分
+将带声调的拼音拆分为以国际音标表示的声母韵母。
+```go
+s, y, t, err := emozi.SplitPinyin("jiǒng")
+if err != nil {
+ panic(err)
+}
+fmt.Println(s, y, tone) // tɕ i̯ʊŋ 上声
+```
diff --git a/codegen/radical/main.go b/codegen/radical/main.go
new file mode 100644
index 0000000..29f929f
--- /dev/null
+++ b/codegen/radical/main.go
@@ -0,0 +1,54 @@
+package main
+
+import (
+ "html/template"
+ "os"
+ "time"
+
+ sql "github.com/FloatTech/sqlite"
+ "github.com/fumiama/emozi"
+)
+
+const head = `// Code generated by codegen/radical. 已经经过修改, 不要手动重新运行.
+
+package emozi
+
+// 部首后备 内嵌的部首到颜文字的映射, 是第二优先查询顺位. 第一顺位是数据库的部首表. 第三位是回落到 🈳️.
+var 部首后备 = map[rune]string{ {{range .}}
+ '{{.R}}': "🈳️",{{end}}
+}
+`
+
+func main() {
+ db := sql.Sqlite{DBPath: emozi.EmoziDatabasePath}
+ err := db.Open(time.Minute)
+ if err != nil {
+ panic(err)
+ }
+ defer db.Close()
+ type r struct {
+ R rune
+ }
+ type sr struct {
+ R string
+ }
+ var s r
+ var ss = []sr{}
+ db.QueryFor("SELECT DISTINCT R FROM emozi;", &s, func() error {
+ ss = append(ss, sr{R: string(s.R)})
+ return nil
+ })
+ t, err := template.New("list").Parse(head)
+ if err != nil {
+ panic(err)
+ }
+ f, err := os.Create("radical.go")
+ if err != nil {
+ panic(err)
+ }
+ defer f.Close()
+ err = t.Execute(f, ss)
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/coder.go b/coder.go
new file mode 100644
index 0000000..9bfd272
--- /dev/null
+++ b/coder.go
@@ -0,0 +1,178 @@
+package emozi
+
+import (
+ "errors"
+ "strconv"
+ "strings"
+ "time"
+
+ sql "github.com/FloatTech/sqlite"
+)
+
+// Coder encoder/decoder
+type Coder struct {
+ db sql.Sqlite
+ isRandom bool
+}
+
+// NewCoder israndom 随机挑选声母韵母的颜文字, 否则固定使用第一个
+func NewCoder(israndom bool, cachettl time.Duration) (c Coder, err error) {
+ c.db.DBPath = EmoziDatabasePath
+ c.isRandom = israndom
+ err = c.db.Open(cachettl)
+ if err != nil {
+ return
+ }
+ err = c.db.Create(主字表名, &字表{})
+ if err != nil {
+ return
+ }
+ err = c.db.Create(附字表名, &字表{})
+ if err != nil {
+ return
+ }
+ err = c.db.Create(部首表名, &部首表{})
+ if err != nil {
+ return
+ }
+ _ = c.db.Query("CREATE INDEX IF NOT EXISTS IE ON "+部首表名+" (E);", nil)
+ return
+}
+
+// Close ...
+func (c *Coder) Close() error {
+ return c.db.Close()
+}
+
+// Encode 从汉字序列生成 EmoziString
+func (c *Coder) Encode(s string, selections ...int) (EmoziString, error) {
+ sb := strings.Builder{}
+ x := &字表{}
+ lst := []字表{}
+ write := func(x *字表) {
+ sb.WriteString(c.查声母(x.S))
+ sb.WriteString(c.查韵母(x.Y))
+ sb.WriteString(c.查声调(x.T))
+ sb.WriteString(c.查部首(x.R))
+ }
+ 多音字计数 := 0
+ for _, ch := range s { // nolint: go-staticcheck
+ lst = lst[:0]
+ err := c.db.FindFor(附字表名, x, "WHERE W="+strconv.Itoa(int(ch)), func() error {
+ lst = append(lst, *x)
+ return nil
+ })
+ if err != nil {
+ lst = lst[:0]
+ err = c.db.FindFor(主字表名, x, "WHERE W="+strconv.Itoa(int(ch)), func() error {
+ lst = append(lst, *x)
+ return nil
+ })
+ }
+ if err != nil || len(lst) == 0 {
+ sb.WriteRune(ch)
+ continue
+ }
+ if len(lst) == 1 {
+ write(x)
+ continue
+ }
+ if len(selections) > 多音字计数 {
+ idx := selections[多音字计数]
+ 多音字计数++
+ if idx >= 0 && idx < len(lst) {
+ write(&lst[idx])
+ continue
+ }
+ }
+ // 多音字
+ sb.WriteString("[")
+ write(&lst[0])
+ for _, x := range lst[1:] {
+ sb.WriteString("|")
+ write(&x)
+ }
+ sb.WriteString("]")
+ }
+ return WrapRawEmoziString(sb.String()), nil
+}
+
+// Add 向主库添加一个新字
+//
+// w: 字, r: 部首, p: 不带声调的拼音(可空), f: 带声调的拼音
+func (c *Coder) Add(w, r, p, f string) error {
+ if p == "" {
+ p = 去调(f)
+ }
+ s, y, t, rw, rr, err := 拆音识字(w, r, p, f)
+ if err != nil {
+ return err
+ }
+ err = c.db.InsertUnique(主字表名, &字表{
+ ID: 颜表ID(rw, s, y, t),
+ W: rw, S: s, Y: y, T: t,
+ R: rr, P: p, F: f,
+ })
+ if err != nil {
+ return errors.New("已有同音同形的字 '" + w + "'")
+ }
+ return nil
+}
+
+// Overlay 向附加库添加一个新字, 覆盖在主库之上
+//
+// w: 字, r: 部首, p: 不带声调的拼音(可空), f: 带声调的拼音
+func (c *Coder) Overlay(w, r, p, f string) error {
+ if p == "" {
+ p = 去调(f)
+ }
+ s, y, t, rw, rr, err := 拆音识字(w, r, p, f)
+ if err != nil {
+ return err
+ }
+ return c.overlay(w, p, f, s, y, t, rw, rr)
+}
+
+func (c *Coder) overlay(w, p, f string, s 声母枚举, y 韵母枚举, t 声调枚举, rw rune, rr rune) error {
+ err := c.db.InsertUnique(附字表名, &字表{
+ ID: 颜表ID(rw, s, y, t),
+ W: rw, S: s, Y: y, T: t,
+ R: rr, P: p, F: f,
+ })
+ if err != nil {
+ return errors.New("已有同音同形的字 '" + w + "'")
+ }
+ return nil
+}
+
+// ChangeOverlay 更改附加库的一项
+func (c *Coder) ChangeOverlay(oldw, oldr, oldf, neww, newr, newf string) error {
+ s, y, t, rw, rr, err := 拆音识字(oldw, oldr, 去调(oldf), oldf)
+ if err != nil {
+ return err
+ }
+ newp := 去调(newf)
+ ns, ny, nt, nrw, nrr, err := 拆音识字(neww, newr, newp, newf)
+ if err != nil {
+ return err
+ }
+ q := "WHERE ID=" + strconv.FormatInt(颜表ID(rw, s, y, t), 10)
+ x := 字表{}
+ err = c.db.Find(附字表名, &x, q)
+ if err != nil {
+ return err
+ }
+ if x.R != rr {
+ return errors.New("提供的旧部首 '" + string(rr) + "' 与记载的 '" + string(x.R) + "' 不符")
+ }
+ err = c.db.Del(附字表名, q)
+ if err != nil {
+ return err
+ }
+ return c.overlay(neww, newp, newf, ns, ny, nt, nrw, nrr)
+}
+
+// OverlayRadical 添加一个部首
+func (c *Coder) OverlayRadical(r rune, e string) error {
+ return c.db.InsertUnique(部首表名, &部首表{R: r, E: e})
+}
diff --git a/coder_test.go b/coder_test.go
new file mode 100644
index 0000000..1396bb1
--- /dev/null
+++ b/coder_test.go
@@ -0,0 +1,29 @@
+package emozi
+
+import (
+ "testing"
+ "time"
+)
+
+func TestEncode(t *testing.T) {
+ c, err := NewCoder(false, time.Minute)
+ if err != nil {
+ t.Fatal(err)
+ }
+ es, err := c.Encode("你好,世界!看看多音字:行。")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(es.String())
+ if es.String() != "🥛👔🐴👤🌹🐱🐴👩,💦🌞😨🌍➕✌😨👨🌾!😭🔐🍉👁️😭🔐🍉👁️🔪🌀🍉🪩🐑🎵🍉🎵👈🌞😨🚼:[👇🦅🧗⛕|🌹👍🧗⛕]。" {
+ t.Fatal("got", es.String())
+ }
+ es, err = c.Encode("你好,世界!指定多音字:银行行。", 1, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(es.String())
+ if es.String() != "🥛👔🐴👤🌹🐱🐴👩,💦🌞😨🌍➕✌😨👨🌾!🐽🌞🐴✋🔪🦅😨🏠🔪🌀🍉🪩🐑🎵🍉🎵👈🌞😨🚼:🐑🎵🧗💰🌹👍🧗⛕👇🦅🧗⛕。" {
+ t.Fatal("got", es.String())
+ }
+}
diff --git a/data.go b/data.go
new file mode 100644
index 0000000..48891b8
--- /dev/null
+++ b/data.go
@@ -0,0 +1,38 @@
+package emozi
+
+import _ "embed"
+
+// 字数据库 数据来自 https://github.com/shuowenjiezi/shuowen
+//
+//var 字数据库 []byte
+
+// DatabasePath 字数据库的路径 如找不到会向对应路径写入内嵌的字数据库
+var EmoziDatabasePath = "字.db"
+
+const (
+ 主字表名 = "emozi"
+ 附字表名 = "altzi"
+ 部首表名 = "radcl"
+)
+
+// 字表 emozi表 定义
+type 字表 struct {
+ ID int64 // ID 高 32 位 W 的 rune, 低 32 位 保留8 S8 Y8 T8
+ W rune
+ S 声母枚举
+ Y 韵母枚举
+ T 声调枚举
+ R rune
+ P string
+ F string
+}
+
+func 颜表ID(w rune, s 声母枚举, y 韵母枚举, t 声调枚举) int64 {
+ return int64((uint64(w) << 32) | (uint64(s) << 16) | (uint64(y) << 8) | (uint64(t)))
+}
+
+// 从表 从部首表
+type 部首表 struct {
+ R rune // R 该部首
+ E string `db:"E,UNIQUE"` // E 该部首对应的颜文字
+}
diff --git a/define.go b/define.go
new file mode 100644
index 0000000..83d012f
--- /dev/null
+++ b/define.go
@@ -0,0 +1,210 @@
+package emozi
+
+import (
+ "strings"
+
+ base14 "github.com/fumiama/go-base16384"
+)
+
+type 声母枚举 uint8
+
+// String 国际音标
+func (sm 声母枚举) String() string {
+ a := sm * 3
+ b := a + 3
+ 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))
+}
+
+const (
+ 声母b 声母枚举 = iota
+ 声母p
+ 声母m
+ 声母f
+ 声母d
+ 声母t
+ 声母n
+ 声母l
+ 声母g
+ 声母k
+ 声母h
+ 声母j
+ 声母q
+ 声母x
+ 声母zh
+ 声母ch
+ 声母sh
+ 声母r
+ 声母z
+ 声母c
+ 声母s
+ 声母yi
+ 声母w
+ 声母yu
+ 声母0
+)
+
+// 声母 可以有多个颜文字与之对应 但有时系统可能无法显示
+var 声母 = [...][]string{
+ // b: 鼻笔八
+ {"👃", "🖊️", "🎱"},
+ // p: 跑跑跑票票牌牌
+ {"🏃", "🏃♀️", "🏃♂️", "🎫", "🎟️", "🃏", "🎴"},
+ // m: 马马猫猫猫猫锚面面门麦米木蜜帽帽帽麦
+ {"🐴", "🐎", "🐱", "🐈", "🐈⬛", "😺", "⚓️", "🍜", "🍝", "🚪", "🌾", "🍚", "🪵", "🍯", "🎩", "👒", "🧢", "🎙️"},
+ // f: 斧肺
+ {"🪓", "🫁"},
+ // d: 刀豆蛋灯灯洞
+ {"🔪", "🫘", "🥚", "💡", "🪔", "🕳️"},
+ // t: 腿糖兔兔桶桃
+ {"🦵", "🍬", "🐰", "🐇", "🪣", "🍑"},
+ // n: 奶鸟牛
+ {"🥛", "🐦", "🐮"},
+ // l: 鹿鹿冷龙龙莲
+ {"🦌", "🫎", "🥶", "🐲", "🐉", "🪷"},
+ // g: 瓜鼓龟狗勾跪跪跪
+ {"🍉", "🥁", "🐢", "🐶", "🪝", "🧎", "🧎♀️", "🧎♂️"},
+ // k: 哭裤
+ {"😭", "👖"},
+ // h: 花花花花花花花花火虎虎猴猴
+ {"🌹", "🌼", "💐", "🌷", "🌸", "🌺", "🥀", "🪻", "🔥", "🐯", "🐅", "🐒", "🐵"},
+ // j: 加减酒酒鸡鸡剑姜镜脚
+ {"➕", "➖", "🍷", "🍺", "🐔", "🐓", "🗡️", "🫚", "🪞", "🦶"},
+ // q: 茄钱钱钱钱钱棋
+ {"🍆", "💰", "💴", "💵", "💶", "💸", "♟️"},
+ // x: 下下虾虾虾雪星星星星熊象蟹
+ {"👇", "⬇️", "🦐", "🍤", "🦞", "❄️", "🌟", "✨", "⭐️", "💫", "🐻", "🐘", "🦀️"},
+ // zh: 猪猪针针
+ {"🐽", "🐷", "🪡", "💉"},
+ // ch: 茶茶车车车车床床除虫
+ {"🍵", "☕️", "🚗", "🚘", "🚙", "🛻", "🛏️", "🛌", "➗", "🐛"},
+ // sh: 水水书书书书书书上上上石山山山树树树蛇鼠鼠鼠珊
+ {"💦", "💧", "📖", "📕", "📗", "📘", "📙", "📚", "⬆️", "☝️", "👆", "🪨", "⛰️", "🏔️", "🗻", "🌲", "🌳", "🌴", "🐍", "🐭", "🐀", "🐁", "🪸"},
+ // r: 肉日日日
+ {"🥩", "🌞", "☀️", "🌅"},
+ // z: 左左左 c: 错错错错 s: 锁伞伞伞伞蒜
+ {"👈", "⬅️", "⬅"}, {"❌", "🙅", "🙅♀️", "🙅♂️"}, {"🔒", "🌂", "☔️", "⛱️", "☂️", "🧄"},
+ // yi: 羊羊牙药盐 w: 袜雾网碗 yu: 雨鱼鱼 0: 两种椅子
+ {"🐑", "🐐", "🦷", "💊", "🧂"}, {"🧦", "🌫️", "🕸️", "🥣"}, {"🐟", "🌧️", "🐠"}, {"🪑", "💺"},
+}
+
+type 韵母枚举 uint8
+
+// String 国际音标
+func (ym 韵母枚举) String() string {
+ return [...]string{
+ "ä", "ɔ", "ɤ", "i", "ɿ", "u", "y", "ɐɚ̯", "aɪ̯", "u̯aɪ̯", "eɪ̯", "u̯eɪ̯", "ɑʊ̯", "i̯ɑʊ̯",
+ "oʊ̯", "i̯oʊ̯", "i̯ä", "u̯ä", "u̯o", "i̯ɛ", "y̯ɛ", "an", "i̯ɛn", "u̯an", "y̯ɛn", "ən", "u̯ən",
+ "in", "yn", "ɑŋ", "i̯ɑŋ", "u̯ɑŋ", "ɤŋ", "iŋ", "u̯əŋ", "ʊŋ", "i̯ʊŋ",
+ }[ym]
+}
+
+const (
+ 韵母a 韵母枚举 = iota
+ 韵母o
+ 韵母e
+ 韵母yi
+ 韵母ri
+ 韵母wu
+ 韵母yu
+ 韵母er
+ 韵母ai
+ 韵母uai
+ 韵母ei
+ 韵母ui
+ 韵母ao
+ 韵母iao
+ 韵母ou
+ 韵母iu
+ 韵母ia
+ 韵母ua
+ 韵母uo
+ 韵母ie
+ 韵母yue
+ 韵母an
+ 韵母ian
+ 韵母uan
+ 韵母yuan
+ 韵母en
+ 韵母un
+ 韵母in
+ 韵母yun
+ 韵母ang
+ 韵母iang
+ 韵母uang
+ 韵母eng
+ 韵母ing
+ 韵母ueng
+ 韵母ong
+ 韵母iong
+)
+
+// 韵母 仅由一种意象表示
+var 韵母 = [...][]string{
+ {"😧", "🤔️"}, {"😲"}, {"😋"}, {"👔", "👗", "👕", "👚"}, {"🌞", "☀️", "🌅"},
+ {string([]rune("🌫️")[0]), "🌫️"}, {"🐟", "🌧️"}, {"👂"},
+ {string([]rune("❤️")[0]), "❤️", "💗", "💓", "🫶", "💕", "💖", "💘", "💙", "💚", "💛", "💜", "💝", "💞", "🧡"}, {"🥢"}, {"😩"}, {"🐢"},
+ {"🐱", "🐈", "🐈⬛", "😺"}, {"💊"}, {"🤮", "🤢"}, {"👉", "➡️"},
+ {"🦷"}, {"🧦"}, {"🌀"}, {string([]rune("✌️")[0]), "✌️"}, {"🌙", "🌕", "🌛", "🌝"}, {"🔐"}, {"🚬"}, {"🥣", "🍚"},
+ {string([]rune("⭕️")[0]), "⭕️"}, {"😐"}, {"😘", "💋"}, {"🎵"}, {string([]rune("☁️")[0]), "☁️"}, {"👍"}, {"🐑"},
+ {string([]rune("🕸️")[0]), "🕸️"}, {"💡", "🪔"}, {"🦅"}, {"🐝"}, {"🌈"}, {"😳"}, // jiong 囧
+}
+
+type 声调枚举 uint8
+
+// String 返回传统调名
+func (t 声调枚举) String() string {
+ return [...]string{
+ "阴平", "阳平", "上声", "去声", "轻声",
+ }[t]
+}
+
+const (
+ 阴平 声调枚举 = iota
+ 阳平
+ 上声
+ 去声
+ 轻声
+)
+
+var 声调 = [...][]string{{"🍉"}, {"🧗", "🧗♀️", "🧗♂️", "🦎"}, {"🐴", "🐎"}, {"😨"}, {"😯"}}
+
+// 校验表 用 校验表长度 个unicode控制字符做校验和验证此序列是由本程序生成而非手写的
+//
+// 具体做法是先对后面的文本做crc32然后取 校验表长度^校验字节数 的模
+var 校验表 = func() []rune {
+ x, err := base14.UTF16BE2UTF8(base14.StringToBytes("\x20\x0b\x20\x0c\x20\x0d\x20\x0e\x20\x0f\x20\x2a\x20\x2b\x20\x2c\x20\x2d\x20\x2e\x20\x60\x20\x61\x20\x62\x20\x63\x20\x64\x20\x65\x20\x66\x20\x68\x20\x69\x20\x6a\x20\x6b\x20\x6c\x20\x6d\x20\x6e\x20\x6f"))
+ if err != nil {
+ panic(err)
+ }
+ return []rune(base14.BytesToString(x))
+}()
+
+// 校验表长度 25
+var 校验表长度 = len(校验表)
+
+// 校验字节数 默认为 3, 不得大于 3
+const 校验字节数 = 3
+
+// 校验模 校验表长度^校验字节数
+var 校验模 = uint32(0)
+
+// 校验倍数 校验表长度乘方表
+var 校验倍数 = func() []uint32 {
+ tab := make([]uint32, 校验字节数)
+ tab[0] = 1
+ for i := 1; i < 校验字节数; i++ {
+ tab[i] = tab[i-1] * uint32(校验表长度)
+ }
+ 校验模 = tab[校验字节数-1] * uint32(校验表长度)
+ return tab
+}()
+
+// 逆校验表 还原校验和用
+var 逆校验表 = func() map[rune]uint8 {
+ m := make(map[rune]uint8, 64)
+ for i, c := range 校验表 {
+ m[c] = uint8(i)
+ }
+ return m
+}()
diff --git a/define_test.go b/define_test.go
new file mode 100644
index 0000000..920ffc3
--- /dev/null
+++ b/define_test.go
@@ -0,0 +1,22 @@
+package emozi
+
+import "testing"
+
+func TestFirstEmojiSingle(t *testing.T) {
+ for i, lst := range 声母 {
+ if len([]rune(lst[0])) != 1 {
+ t.Fatal("声母", i, "长度", len([]rune(lst[0])), "字", lst[0])
+ }
+ }
+ t.Log(string([]rune("🌫️")[0]), string([]rune("❤️")[0]), string([]rune("✌️")[0]), string([]rune("⭕️")[0]), string([]rune("☁️")[0]), string([]rune("🕸️")[0]))
+ for i, lst := range 韵母 {
+ if len([]rune(lst[0])) != 1 {
+ t.Fatal("韵母", i, "长度", len([]rune(lst[0])), "字", lst[0])
+ }
+ }
+ for i, lst := range 声调 {
+ if len([]rune(lst[0])) != 1 {
+ t.Fatal("声调", i, "长度", len([]rune(lst[0])), "字", lst[0])
+ }
+ }
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..21df239
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,29 @@
+module github.com/fumiama/emozi
+
+go 1.20
+
+require (
+ github.com/FloatTech/sqlite v1.6.3
+ github.com/fumiama/go-base16384 v1.7.0
+ github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5
+)
+
+require (
+ github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b // indirect
+ github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
+ github.com/google/uuid v1.3.0 // indirect
+ github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
+ github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d // indirect
+ github.com/mattn/go-isatty v0.0.16 // indirect
+ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
+ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
+ golang.org/x/text v0.3.7 // indirect
+ modernc.org/libc v1.21.5 // indirect
+ modernc.org/mathutil v1.5.0 // indirect
+ modernc.org/memory v1.4.0 // indirect
+ modernc.org/sqlite v1.20.0 // indirect
+)
+
+replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.20.0-with-win386
+
+replace github.com/remyoudompheng/bigfft => github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..d739478
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,43 @@
+github.com/FloatTech/sqlite v1.6.3 h1:MQkqBNlkPuCoKQQgoNLuTL/2Ci3tBTFAnVYBdD0Wy4M=
+github.com/FloatTech/sqlite v1.6.3/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
+github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
+github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
+github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew=
+github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b h1:Zt3pFQditAdWTHCOVkiloc9ZauBoWrb37guFV4iIRvE=
+github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA=
+github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
+github.com/fumiama/sqlite3 v1.20.0-with-win386 h1:ZR1AXGBEtkfq9GAXehOVcwn+aaCG8itrkgEsz4ggx5k=
+github.com/fumiama/sqlite3 v1.20.0-with-win386/go.mod h1:Os58MHwYCcYZCy2PGChBrQtBAw5/LS1ZZOkfc+C/I7s=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:qSmEGTgjkESUX5kPMSGJ4pcBUtYVDdkNzMrjQyvRvp0=
+github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:x7SghIWwLVcJObXbjK7S2ENsT1cAcdJcPl7dRaSFog0=
+github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d h1:hTRDIpJ1FjS9ULJuEzu69n3qTgc18eI+ztw/pJv47hs=
+github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d/go.mod h1:7xD3p0XnHvJFQ3t/stEJd877CSIMkH/fACVWen5pYnc=
+github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5 h1:wnbHIeP1UX8ClYEWKGnw66PfYvReCHu9G5lXSte3Sqc=
+github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5/go.mod h1:7KaV9YIR92M1FpbczAcfYQ3UZ5ayT27pNtunDmXvLBo=
+github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
+modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
+modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
+modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
+modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
diff --git a/lookup.go b/lookup.go
new file mode 100644
index 0000000..5b28bf4
--- /dev/null
+++ b/lookup.go
@@ -0,0 +1,53 @@
+package emozi
+
+import (
+ "math/rand"
+ "strconv"
+)
+
+var 空 = "🈳️"
+
+func (c *Coder) 查声母(s 声母枚举) string {
+ lst := 声母[s]
+ if len(lst) == 0 {
+ return 空
+ }
+ if len(lst) == 1 || !c.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) 查声调(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) 查部首(r rune) string {
+ x := &部首表{}
+ err := c.db.Find(部首表名, x, "WHERE R="+strconv.Itoa(int(r)))
+ if err == nil && len(x.E) > 0 && x.E != 空 {
+ return x.E
+ }
+ if e, ok := 部首后备[r]; ok {
+ return e
+ }
+ return 空
+}
diff --git a/pinyin.go b/pinyin.go
new file mode 100644
index 0000000..d9b28a3
--- /dev/null
+++ b/pinyin.go
@@ -0,0 +1,336 @@
+package emozi
+
+import (
+ "errors"
+ "strings"
+)
+
+var smap = map[string]声母枚举{
+ "b": 声母b,
+ "p": 声母p,
+ "m": 声母m,
+ "f": 声母f,
+ "d": 声母d,
+ "t": 声母t,
+ "n": 声母n,
+ "l": 声母l,
+ "g": 声母g,
+ "k": 声母k,
+ "h": 声母h,
+ "j": 声母j,
+ "q": 声母q,
+ "x": 声母x,
+ "r": 声母r,
+ "w": 声母w,
+}
+
+const 双字声母 = "zcs"
+
+var amap = map[string]韵母枚举{
+ "a": 韵母a,
+ "ai": 韵母ai,
+ "ao": 韵母ao,
+ "an": 韵母an,
+ "ang": 韵母ang,
+}
+
+var wamap = map[string]韵母枚举{
+ "a": 韵母ua,
+ "ai": 韵母uai,
+ "an": 韵母uan,
+ "ang": 韵母uang,
+}
+
+var omap = map[string]韵母枚举{
+ "o": 韵母o,
+ "ou": 韵母ou,
+ "ong": 韵母ong,
+}
+
+var emap = map[string]韵母枚举{
+ "e": 韵母e,
+ "er": 韵母er,
+ "ei": 韵母ei,
+ "en": 韵母en,
+ "eng": 韵母eng,
+}
+
+var wemap = map[string]韵母枚举{
+ "ei": 韵母ei,
+ "en": 韵母en,
+ "eng": 韵母ueng,
+}
+
+var imap = map[string]韵母枚举{
+ "i": 韵母yi,
+ "iao": 韵母iao,
+ "iu": 韵母iu,
+ "ia": 韵母ia,
+ "ie": 韵母ie,
+ "ian": 韵母ian,
+ "in": 韵母in,
+ "iang": 韵母iang,
+ "ing": 韵母ing,
+ "iong": 韵母iong,
+}
+
+var umap = map[string]韵母枚举{
+ "u": 韵母wu,
+ "uai": 韵母uai,
+ "ui": 韵母ui,
+ "ua": 韵母ua,
+ "uo": 韵母uo,
+ "uan": 韵母uan,
+ "un": 韵母un,
+ "uang": 韵母uang,
+ "ueng": 韵母ueng,
+}
+
+var yumap = map[string]韵母枚举{
+ "u": 韵母yu,
+ "ue": 韵母yue,
+ "uan": 韵母yuan,
+ "un": 韵母yun,
+ "ü": 韵母yu,
+ "üe": 韵母yue,
+ "üan": 韵母yuan,
+ "ün": 韵母yun,
+ "v": 韵母yu,
+ "ve": 韵母yue,
+ "van": 韵母yuan,
+ "vn": 韵母yun,
+}
+
+func combine(maps ...map[string]韵母枚举) map[string]韵母枚举 {
+ newmap := make(map[string]韵母枚举, 128)
+ for _, m := range maps {
+ for k, v := range m {
+ newmap[k] = v
+ }
+ }
+ return newmap
+}
+
+var aoeiu = combine(amap, omap, emap, imap, umap)
+
+var aoeu = combine(amap, omap, emap, umap)
+
+const (
+ 阴平字母 = "āōēīūǖ"
+ 阳平字母 = "áóéíúǘń"
+ 上声字母 = "ǎǒěǐǔǚň"
+ 去声字母 = "àòèìùǜ"
+ G = 'ɡ'
+ A = 'ɑ'
+)
+
+var notonemap = map[rune]string{
+ 'ā': "a", 'á': "a", 'ǎ': "a", 'à': "a",
+ 'ō': "o", 'ó': "o", 'ǒ': "o", 'ò': "o",
+ 'ē': "e", 'é': "e", 'ě': "e", 'è': "e",
+ 'ī': "i", 'í': "i", 'ǐ': "i", 'ì': "i",
+ 'ū': "u", 'ú': "u", 'ǔ': "u", 'ù': "u",
+ 'ǖ': "ü", 'ǘ': "ü", 'ǚ': "ü", 'ǜ': "ü",
+ G: "g", A: "a", 'ń': "n", 'ň': "n",
+}
+
+func 去调(pf string) string {
+ sb := strings.Builder{}
+ for _, c := range pf {
+ if nc, ok := notonemap[c]; ok {
+ sb.WriteString(nc)
+ } else {
+ sb.WriteRune(c)
+ }
+ }
+ return sb.String()
+}
+
+// 识调 从拼音获得声调
+func 识调(pf string) 声调枚举 {
+ switch {
+ case strings.ContainsAny(pf, 阴平字母):
+ return 阴平
+ case strings.ContainsAny(pf, 阳平字母):
+ return 阳平
+ case strings.ContainsAny(pf, 上声字母):
+ return 上声
+ case strings.ContainsAny(pf, 去声字母):
+ return 去声
+ }
+ return 轻声
+}
+
+// 拆音 拆分拼音为声母韵母
+func 拆音(p string) (sm 声母枚举, ym 韵母枚举, err error) {
+ if len(p) == 1 {
+ sm = 声母0
+ // 韵母ê, 因为文字稀少, 并入 ie
+ if p == "ê" {
+ ym = 韵母ie
+ return
+ }
+ if y, ok := aoeiu[p]; ok {
+ ym = y
+ return
+ }
+ err = errors.New("无法识别零声母拼音" + p)
+ return
+ }
+ if s, ok := smap[p[:1]]; ok {
+ sm = s
+ ok = false
+ switch p[1:2] {
+ case "a":
+ if p[:1] == "w" {
+ ym, ok = wamap[p[1:]]
+ } else {
+ ym, ok = amap[p[1:]]
+ }
+ case "o":
+ if p[:1] == "w" {
+ ym = 韵母uo
+ ok = true
+ } else {
+ ym, ok = omap[p[1:]]
+ }
+ case "e":
+ if p[:1] == "w" {
+ ym, ok = wemap[p[1:]]
+ } else {
+ ym, ok = emap[p[1:]]
+ }
+ case "i":
+ if p[:1] == "r" {
+ ym = 韵母ri
+ ok = true
+ } else {
+ ym, ok = imap[p[1:]]
+ }
+ case "u":
+ if strings.Contains("jqx", p[:1]) {
+ ym, ok = yumap[p[1:]]
+ } else {
+ ym, ok = umap[p[1:]]
+ if !ok {
+ ym, ok = yumap[p[1:]]
+ }
+ }
+ case "v", "ü"[:1]:
+ ym, ok = yumap[p[1:]]
+ }
+ if !ok {
+ err = errors.New("无法识别拼音" + p + "的韵母部分" + p[1:])
+ }
+ return
+ }
+ ok := false
+ if strings.Contains(双字声母, p[:1]) {
+ if p[1:2] == "h" { // zh ch sh
+ switch p[:1] {
+ case "z":
+ sm = 声母zh
+ case "c":
+ sm = 声母ch
+ case "s":
+ sm = 声母sh
+ }
+ ym, ok = aoeu[p[2:]]
+ if !ok {
+ if p[2:] == "i" {
+ ym = 韵母ri
+ } else {
+ err = errors.New("无法识别拼音" + p)
+ }
+ }
+ return
+ }
+ switch p[:1] {
+ case "z":
+ sm = 声母z
+ case "c":
+ sm = 声母c
+ case "s":
+ sm = 声母s
+ }
+ ym, ok = aoeu[p[1:]]
+ if !ok {
+ if p[1:] == "i" {
+ ym = 韵母ri
+ } else {
+ err = errors.New("无法识别拼音" + p)
+ }
+ }
+ return
+ }
+ if p[:1] == "y" { // /j/ or /y/
+ if strings.Contains("uvü"[:3], p[1:2]) { // /y/
+ sm = 声母yu
+ ym, ok = yumap[p[1:]]
+ if !ok {
+ err = errors.New("无法识别拼音" + p)
+ }
+ return
+ }
+ if p[1:] == "ong" { // yong
+ sm = 声母yu
+ ym = 韵母iong
+ ok = true
+ return
+ }
+ sm = 声母yi
+ ym, ok = aoeiu[p[1:]]
+ if !ok {
+ err = errors.New("无法识别拼音" + p)
+ }
+ return
+ }
+ sm = 声母0
+ ym, ok = aoeiu[p]
+ if !ok {
+ err = errors.New("无法识别拼音" + p)
+ }
+ return
+}
+
+func 拆音识字(w, r, p, f string) (s 声母枚举, y 韵母枚举, t 声调枚举, rw, rr rune, err error) {
+ myp := 去调(f)
+ s, y, err = 拆音(p)
+ if err != nil {
+ return
+ }
+ mys, myy, err := 拆音(myp)
+ if err != nil {
+ return
+ }
+ if mys != s || myy != y {
+ err = errors.New("无声调拼音" + p + "与有声调拼音" + f + "不符")
+ return
+ }
+ t = 识调(f)
+ rws := []rune(w)
+ if len(rws) != 1 {
+ err = errors.New("无法正确识别文字" + w)
+ return
+ }
+ rw = rws[0]
+ rrs := []rune(r)
+ if len(rrs) != 1 {
+ err = errors.New("无法正确识别部首" + w)
+ return
+ }
+ rr = rrs[0]
+ return
+}
+
+// SplitPinyin 拆分带声调拼音
+func SplitPinyin(pf string) (sm, ym, sd string, err error) {
+ p := 去调(pf)
+ s, y, err := 拆音(p)
+ if err != nil {
+ return
+ }
+ t := 识调(pf)
+ println(s, y, t)
+ return s.String(), y.String(), t.String(), nil
+}
diff --git a/pinyin_test.go b/pinyin_test.go
new file mode 100644
index 0000000..0f289d4
--- /dev/null
+++ b/pinyin_test.go
@@ -0,0 +1,46 @@
+package emozi
+
+import "testing"
+
+func TestSplitPinyin(t *testing.T) {
+ s, y, tone, err := SplitPinyin("yōng")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(s, y, tone)
+ if s+y+tone != "ɥi̯ʊŋ阴平" {
+ t.Fail()
+ }
+ s, y, tone, err = SplitPinyin("hóng")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(s, y, tone)
+ if s+y+tone != "xʊŋ阳平" {
+ t.Fail()
+ }
+ s, y, tone, err = SplitPinyin("yǜn")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(s, y, tone)
+ if s+y+tone != "ɥyn去声" {
+ t.Fail()
+ }
+ s, y, tone, err = SplitPinyin("jiǒng")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(s, y, tone)
+ if s+y+tone != "tɕi̯ʊŋ上声" {
+ t.Fail()
+ }
+ s, y, tone, err = SplitPinyin("e")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(s, y, tone)
+ if s+y+tone != "0ɤ轻声" {
+ t.Fail()
+ }
+}
diff --git a/preprocess/main.go b/preprocess/main.go
new file mode 100644
index 0000000..2dfb8ae
--- /dev/null
+++ b/preprocess/main.go
@@ -0,0 +1,81 @@
+package main
+
+// 数据来自 https://github.com/shuowenjiezi/shuowen
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/liuzl/gocc"
+
+ "github.com/fumiama/emozi"
+)
+
+type data struct {
+ W string `json:"wordhead"`
+ R string `json:"radical"`
+ P string `json:"pinyin"`
+ F string `json:"pinyin_full"`
+ A []string `json:"pinyin_alternative"`
+}
+
+func main() {
+ x := data{}
+ t2s, err := gocc.New("t2s")
+ if err != nil {
+ panic(fmt.Sprintf("ERROR: creating gocc: %v", err))
+ }
+ _ = os.RemoveAll(emozi.EmoziDatabasePath)
+ c, err := emozi.NewCoder(false, time.Minute)
+ if err != nil {
+ panic(fmt.Sprintf("ERROR: creating emozi coder: %v", err))
+ }
+ for i := 1; i <= 9833; i++ {
+ f, err := os.Open(fmt.Sprintf("./data/%d.json", i))
+ if err != nil {
+ panic(fmt.Sprintf("ERROR: opening data/%d.json: %v", i, err))
+ }
+ x.A = x.A[:0]
+ err = json.NewDecoder(f).Decode(&x)
+ if err != nil {
+ panic(fmt.Sprintf("ERROR: decoding data/%d.json: %v", i, err))
+ }
+ _ = f.Close()
+ x.P = strings.ReplaceAll(x.P, string(emozi.G), "g")
+ if len(x.P) == 0 {
+ panic(fmt.Sprintf("ERROR: decoding data/%d.json: p: %s, f: %s", i, x.P, x.F))
+ }
+ insert := func(w string) error {
+ err = c.Add(w, x.R, x.P, x.F)
+ if err != nil {
+ return fmt.Errorf("inserting table emozi of data/%d.json: %v", i, err)
+ }
+ for _, a := range x.A {
+ err = c.Add(w, x.R, "", a)
+ if err != nil {
+ return fmt.Errorf("inserting table emozi of data/%d.json, alter %s: %v", i, a, err)
+ }
+ }
+ return nil
+ }
+ fmt.Print("\r[", i, "/9833] Insert char: ", x.W, " ")
+ err = insert(x.W)
+ if err != nil {
+ fmt.Println("\n\t\tWARN:", err)
+ }
+ sc, err := t2s.Convert(x.W)
+ if err != nil {
+ continue
+ }
+ if sc != x.W {
+ fmt.Print("\r[", i, "/9833] insert simplified char: ", sc, " ")
+ err = insert(sc)
+ if err != nil {
+ fmt.Println("\n\t\tWARN:", err)
+ }
+ }
+ }
+}
diff --git a/radical.go b/radical.go
new file mode 100644
index 0000000..37de774
--- /dev/null
+++ b/radical.go
@@ -0,0 +1,547 @@
+// Code generated by codegen/radical. 已经经过修改, 不要手动重新运行.
+
+package emozi
+
+// 部首后备 内嵌的部首到颜文字的映射, 是第二优先查询顺位. 第一顺位是数据库的部首表. 第三位是回落到 🈳️.
+var 部首后备 = map[rune]string{
+ '一': "1⃣️",
+ '丄': "☝️",
+ '示': "😇",
+ '三': "3⃣️",
+ '王': "🫅",
+ '玉': "📿️",
+ '玨': "💎",
+ '气': "🌬",
+ '士': "💼",
+ '丨': "🥖",
+ '屮': "🌱",
+ '艸': "🍀",
+ '蓐': "🧣",
+ '茻': "🌿",
+ '小': "⏳",
+ '八': "8⃣️",
+ '釆': "🙌",
+ '半': "🐂",
+ '牛': "🐮",
+ '犛': "🦬",
+ '告': "🗣️",
+ '口': "👄",
+ '人': "👤",
+ '凵': "💋",
+ '吅': "😱",
+ '哭': "😭",
+ '走': "🏃",
+ '止': "🦶",
+ '癶': "🐾",
+ '步': "👣",
+ '此': "⛷️",
+ '正': "🎯",
+ '是': "⚖",
+ '辵': "🚶",
+ '彳': "🚦",
+ '廴': "🚥",
+ '㢟': "🈳️",
+ '行': "⛕",
+ '齒': "🈳️",
+ '牙': "🈳️",
+ '足': "🈳️",
+ '疋': "🈳️",
+ '品': "🈳️",
+ '龠': "🈳️",
+ '冊': "🈳️",
+ '㗊': "🈳️",
+ '舌': "👅",
+ '干': "🈳️",
+ '𧮫': "🈳️",
+ '只': "🈳️",
+ '㕯': "🈳️",
+ '句': "🈳️",
+ '丩': "🈳️",
+ '古': "🏺",
+ '十': "🔟",
+ '卅': "🌍",
+ '言': "💬",
+ '田': "👨🌾",
+ '誩': "🈳️",
+ '音': "🎵",
+ '䇂': "🈳️",
+ '丵': "🈳️",
+ '菐': "🈳️",
+ '𠬞': "🈳️",
+ '𠬜': "🈳️",
+ '共': "🈳️",
+ '異': "🈳️",
+ '舁': "🈳️",
+ '𦥑': "🈳️",
+ '䢅': "🈳️",
+ '爨': "🈳️",
+ '革': "🈳️",
+ '鬲': "🈳️",
+ '䰜': "🈳️",
+ '爪': "🤏",
+ '丮': "🈳️",
+ '鬥': "👊",
+ '又': "🈳️",
+ '𠂇': "🈳️",
+ '史': "🈳️",
+ '支': "🈳️",
+ '𦘒': "🈳️",
+ '聿': "✍",
+ '畫': "🎨",
+ '隶': "🈳️",
+ '臤': "🈳️",
+ '臣': "🈳️",
+ '殳': "🈳️",
+ '殺': "🪚",
+ '𠘧': "🈳️",
+ '寸': "🈳️",
+ '皮': "🈳️",
+ '㼱': "🈳️",
+ '攴': "🈳️",
+ '女': "👩",
+ '教': "🈳️",
+ '卜': "🔮",
+ '用': "🈳️",
+ '爻': "🈳️",
+ '㸚': "🈳️",
+ '𡕥': "🈳️",
+ '目': "👁️",
+ '䀠': "👀",
+ '眉': "🤨",
+ '盾': "🈳️",
+ '自': "👃",
+ '𪞶': "🈳️",
+ '鼻': "👃",
+ '皕': "🈳️",
+ '習': "🈳️",
+ '羽': "🪶",
+ '隹': "🐦",
+ '奞': "🈳️",
+ '雈': "🈳️",
+ '𦫳': "🈳️",
+ '𥄕': "🈳️",
+ '羊': "🐑",
+ '羴': "🈳️",
+ '瞿': "🈳️",
+ '雔': "🈳️",
+ '雥': "🈳️",
+ '鳥': "🦢",
+ '烏': "🐦⬛",
+ '𠦒': "🈳",
+ '冓': "🈳️",
+ '幺': "🈳️",
+ '𢆶': "🈳️",
+ '叀': "🈳️",
+ '玄': "🈳️",
+ '予': "🈳️",
+ '放': "🈳️",
+ '𠬪': "🈳️",
+ '𣦼': "🈳️",
+ '歺': "🈳️",
+ '死': "🈳️",
+ '冎': "🈳️",
+ '骨': "🈳️",
+ '肉': "🈳️",
+ '筋': "🈳️",
+ '刀': "🔪",
+ '刃': "🔪",
+ '㓞': "🈳️",
+ '丯': "🈳️",
+ '耒': "🈳️",
+ '角': "🥐",
+ '竹': "🎋",
+ '箕': "🈳️",
+ '丌': "🈳️",
+ '左': "👈",
+ '工': "🈳️",
+ '㠭': "🈳️",
+ '巫': "🈳️",
+ '甘': "🈳️",
+ '曰': "🈳️",
+ '乃': "🈳️",
+ '丂': "🈳️",
+ '可': "🈳️",
+ '兮': "🈳️",
+ '号': "🈳️",
+ '亏': "🈳️",
+ '旨': "🈳️",
+ '喜': "🈳️",
+ '壴': "🈳️",
+ '鼓': "🈳️",
+ '豈': "🈳️",
+ '豆': "🈳️",
+ '豊': "🈳️",
+ '豐': "🈳️",
+ '䖒': "🈳️",
+ '虍': "🈳️",
+ '虎': "🈳️",
+ '虤': "🈳️",
+ '皿': "🈳️",
+ '𠙴': "🈳️",
+ '去': "🈳️",
+ '血': "🈳️",
+ '丶': "🈳️",
+ '丹': "🈳️",
+ '青': "🈳️",
+ '井': "🈳️",
+ '皀': "🈳️",
+ '鬯': "🈳️",
+ '食': "🈳️",
+ '亼': "🈳️",
+ '會': "🈳️",
+ '倉': "🈳️",
+ '入': "🈳️",
+ '缶': "🈳️",
+ '矢': "🈳️",
+ '高': "🈳️",
+ '冂': "🈳️",
+ '𩫖': "🈳️",
+ '京': "🈳️",
+ '亯': "🈳️",
+ '㫗': "🈳️",
+ '畗': "🈳️",
+ '㐭': "🈳️",
+ '嗇': "🈳️",
+ '來': "🈳️",
+ '麥': "🈳️",
+ '夊': "🈳️",
+ '舛': "🈳️",
+ '舜': "🈳️",
+ '韋': "🈳️",
+ '弟': "🈳️",
+ '夂': "🈳️",
+ '久': "🈳️",
+ '桀': "🈳️",
+ '木': "🈳️",
+ '東': "🈳️",
+ '林': "🈳️",
+ '才': "🈳️",
+ '叒': "🈳️",
+ '之': "🈳️",
+ '帀': "🈳️",
+ '出': "🈳️",
+ '𣎵': "🈳️",
+ '生': "🈳️",
+ '乇': "🈳️",
+ '𠂹': "🈳️",
+ '𠌶': "🈳️",
+ '華': "🈳️",
+ '𥝌': "🈳️",
+ '稽': "🈳️",
+ '巢': "🈳️",
+ '桼': "🈳️",
+ '束': "🈳️",
+ '㯻': "🈳️",
+ '囗': "🈳️",
+ '員': "🈳️",
+ '貝': "🈳️",
+ '邑': "🈳️",
+ '𨛜': "🈳️",
+ '日': "🈳️",
+ '旦': "🈳️",
+ '倝': "🈳️",
+ '㫃': "🈳️",
+ '冥': "🈳️",
+ '晶': "🈳️",
+ '月': "🈳️",
+ '有': "🈳️",
+ '朙': "🈳️",
+ '囧': "🈳️",
+ '夕': "🌇",
+ '多': "🪩",
+ '毌': "🈳️",
+ '𢎘': "🈳️",
+ '𣐺': "🈳️",
+ '𠧪': "🈳️",
+ '齊': "🈳️",
+ '朿': "🈳️",
+ '片': "🈳️",
+ '鼎': "🈳️",
+ '克': "🈳️",
+ '彔': "🈳️",
+ '禾': "🈳️",
+ '秝': "🈳️",
+ '黍': "🈳️",
+ '香': "🈳️",
+ '米': "🈳️",
+ '毇': "🈳️",
+ '臼': "🈳️",
+ '凶': "🈳️",
+ '朩': "🈳️",
+ '𣏟': "🈳️",
+ '麻': "🈳️",
+ '尗': "🈳️",
+ '耑': "🈳️",
+ '韭': "🈳️",
+ '瓜': "🈳️",
+ '瓠': "🈳️",
+ '宀': "🏠",
+ '宮': "🏛",
+ '呂': "🩻",
+ '穴': "🕳️",
+ '㝱': "🈳️",
+ '疒': "😷",
+ '冖': "🗃",
+ '𠔼': "🈳️",
+ '冃': "🈳️",
+ '㒳': "🈳️",
+ '网': "🈳️",
+ '襾': "🈳️",
+ '巾': "🧣",
+ '巿': "🈳️",
+ '帛': "🈳️",
+ '白': "⚪",
+ '㡀': "🈳️",
+ '黹': "🈳️",
+ '𠤎': "🈳️",
+ '匕': "🈳️",
+ '从': "🈳️",
+ '比': "🈳️",
+ '北': "🈳️",
+ '丘': "🈳️",
+ '㐺': "🈳️",
+ '𡈼': "🈳️",
+ '重': "🈳️",
+ '臥': "🈳️",
+ '身': "🈳️",
+ '㐆': "🈳️",
+ '衣': "🈳️",
+ '裘': "🈳️",
+ '老': "🈳️",
+ '毛': "🈳️",
+ '毳': "🈳️",
+ '尸': "🈳️",
+ '尺': "🈳️",
+ '尾': "🈳️",
+ '履': "🈳️",
+ '舟': "🛶",
+ '方': "🈳️",
+ '儿': "🈳️",
+ '兄': "🈳️",
+ '兂': "🈳️",
+ '皃': "🈳️",
+ '𠑹': "🈳️",
+ '先': "🈳️",
+ '禿': "🈳️",
+ '見': "🈳️",
+ '覞': "🈳️",
+ '欠': "🈳️",
+ '㱃': "🈳️",
+ '㳄': "🈳️",
+ '旡': "🈳️",
+ '頁': "🈳️",
+ '𦣻': "🈳️",
+ '面': "🈳️",
+ '丏': "🈳️",
+ '首': "🈳️",
+ '𥄉': "🈳️",
+ '須': "🈳️",
+ '彡': "🈳️",
+ '彣': "🈳️",
+ '文': "🈳️",
+ '髟': "🈳️",
+ '后': "🈳️",
+ '司': "🈳️",
+ '卮': "🈳️",
+ '卩': "🈳️",
+ '印': "🈳️",
+ '色': "🈳️",
+ '𠨍': "🈳️",
+ '辟': "🈳️",
+ '勹': "🈳️",
+ '包': "🈳️",
+ '茍': "🈳️",
+ '鬼': "🈳️",
+ '甶': "🈳️",
+ '厶': "🈳️",
+ '嵬': "🈳️",
+ '山': "🈳️",
+ '屾': "🈳️",
+ '屵': "🈳️",
+ '广': "🈳️",
+ '厂': "🈳️",
+ '丸': "🈳️",
+ '危': "🈳️",
+ '石': "🈳️",
+ '長': "🈳️",
+ '勿': "🈳️",
+ '冄': "🈳️",
+ '而': "🈳️",
+ '豕': "🈳️",
+ '㣇': "🈳️",
+ '彑': "🈳️",
+ '豚': "🈳️",
+ '豸': "🈳️",
+ '𤉡': "🈳️",
+ '易': "🈳️",
+ '象': "🈳️",
+ '馬': "🈳️",
+ '𢊁': "🈳️",
+ '鹿': "🈳️",
+ '麤': "🈳️",
+ '㲋': "🈳️",
+ '兔': "🈳️",
+ '萈': "🈳️",
+ '犬': "🈳️",
+ '㹜': "🈳️",
+ '鼠': "🈳️",
+ '能': "🈳️",
+ '熊': "🈳️",
+ '火': "🈳️",
+ '炎': "🈳️",
+ '黑': "🈳️",
+ '囪': "🈳️",
+ '焱': "🈳️",
+ '炙': "🈳️",
+ '赤': "🈳️",
+ '大': "🈳️",
+ '亦': "🈳️",
+ '夨': "🈳️",
+ '夭': "🈳️",
+ '交': "🈳️",
+ '尣': "🈳️",
+ '壺': "🈳️",
+ '壹': "🈳️",
+ '㚔': "🈳️",
+ '奢': "🈳️",
+ '亢': "🈳️",
+ '夲': "🈳️",
+ '夰': "🈳️",
+ '亣': "🈳️",
+ '夫': "🈳️",
+ '立': "🈳️",
+ '竝': "🈳️",
+ '囟': "🈳️",
+ '思': "🈳️",
+ '心': "🈳️",
+ '惢': "🈳️",
+ '水': "🈳️",
+ '沝': "🈳️",
+ '瀕': "🈳️",
+ '𡿨': "🈳️",
+ '巜': "🈳️",
+ '川': "🈳️",
+ '泉': "🈳️",
+ '灥': "🈳️",
+ '永': "🈳️",
+ '𠂢': "🈳️",
+ '谷': "🈳️",
+ '仌': "🈳️",
+ '雨': "🈳️",
+ '雲': "🈳️",
+ '魚': "🈳️",
+ '𩺰': "🈳️",
+ '燕': "🈳️",
+ '龍': "🈳️",
+ '飛': "🈳️",
+ '非': "🈳️",
+ '卂': "🈳️",
+ '𠃉': "🈳️",
+ '不': "🈳️",
+ '至': "🈳️",
+ '西': "🈳️",
+ '鹵': "🈳️",
+ '鹽': "🈳️",
+ '戶': "🈳️",
+ '門': "🈳️",
+ '耳': "🈳️",
+ '𦣞': "🈳️",
+ '手': "✋",
+ '𠦬': "🈳️",
+ '毋': "🈳️",
+ '民': "🈳️",
+ '丿': "🈳️",
+ '𠂆': "🈳️",
+ '乁': "🈳️",
+ '氏': "🈳️",
+ '氐': "🈳️",
+ '戈': "🈳️",
+ '戉': "🈳️",
+ '我': "🈳️",
+ '亅': "🈳️",
+ '珡': "🈳️",
+ '𠃊': "🈳️",
+ '亾': "🈳️",
+ '匸': "🈳️",
+ '匚': "🈳️",
+ '曲': "🈳️",
+ '甾': "🈳️",
+ '瓦': "🈳️",
+ '弓': "🈳️",
+ '弜': "🈳️",
+ '弦': "🈳️",
+ '系': "🈳️",
+ '糸': "🈳️",
+ '素': "🈳️",
+ '絲': "🈳️",
+ '率': "🈳️",
+ '虫': "🈳️",
+ '䖵': "🈳️",
+ '蟲': "🈳️",
+ '風': "🈳️",
+ '它': "🈳️",
+ '龜': "🈳️",
+ '黽': "🈳️",
+ '卵': "🈳️",
+ '二': "🈳️",
+ '土': "🈳️",
+ '垚': "🈳️",
+ '堇': "🈳️",
+ '里': "🈳️",
+ '畕': "🈳️",
+ '黃': "🈳️",
+ '男': "🈳️",
+ '力': "🈳️",
+ '劦': "🈳️",
+ '金': "💰",
+ '幵': "🈳️",
+ '勺': "🈳️",
+ '几': "🈳️",
+ '且': "🈳️",
+ '斤': "🈳️",
+ '斗': "🈳️",
+ '矛': "🈳️",
+ '車': "🈳️",
+ '𠂤': "🈳️",
+ '𨸏': "🈳️",
+ '𨺅': "🈳️",
+ '厽': "🈳️",
+ '四': "🈳️",
+ '宁': "🈳️",
+ '叕': "🈳️",
+ '亞': "🈳️",
+ '五': "🈳️",
+ '六': "🈳️",
+ '七': "🈳️",
+ '九': "🈳️",
+ '禸': "🈳️",
+ '嘼': "🈳️",
+ '甲': "🈳️",
+ '乙': "🈳️",
+ '丙': "🈳️",
+ '丁': "🈳️",
+ '戊': "🈳️",
+ '己': "🈳️",
+ '巴': "🈳️",
+ '庚': "🈳️",
+ '辛': "🈳️",
+ '辡': "🈳️",
+ '壬': "🈳️",
+ '癸': "🈳️",
+ '子': "🚼",
+ '了': "🈳️",
+ '孨': "🈳️",
+ '𠫓': "🈳️",
+ '丑': "🈳️",
+ '寅': "🈳️",
+ '戼': "🈳️",
+ '辰': "🈳️",
+ '巳': "🈳️",
+ '午': "🈳️",
+ '未': "🈳️",
+ '申': "🈳️",
+ '酉': "🈳️",
+ '酋': "🈳️",
+ '戌': "🈳️",
+ '亥': "🈳️",
+}
diff --git a/string.go b/string.go
new file mode 100644
index 0000000..fa49c86
--- /dev/null
+++ b/string.go
@@ -0,0 +1,63 @@
+package emozi
+
+import (
+ "hash/crc32"
+ "strings"
+
+ base14 "github.com/fumiama/go-base16384"
+)
+
+// EmoziString 一个颜文字汉字转写串, 包含串头 校验字节数*2 字节校验和
+type EmoziString string
+
+// WrapRawEmoziString 为不包含串头的转写串加一个头使其成为合法 EmoziString
+func WrapRawEmoziString(s string) EmoziString {
+ rs := []rune(s)
+ if len(rs) < 4 {
+ return ""
+ }
+ h := crc32.NewIEEE()
+ h.Write(base14.StringToBytes(s))
+ sum := h.Sum32() % 校验模
+ sb := strings.Builder{}
+ buf := [校验字节数]uint8{}
+ for i := 校验字节数 - 1; i >= 0; i-- {
+ buf[i] = uint8((sum / 校验倍数[i]) % uint32(校验表长度))
+ }
+ for i, n := range buf {
+ sb.WriteRune(rs[i])
+ sb.WriteRune(校验表[n])
+ }
+ sb.WriteString(string(rs[len(buf):]))
+ return EmoziString(sb.String())
+}
+
+// String 输出不包含串头的转写串
+func (es EmoziString) String() string {
+ if !es.IsValid() {
+ return "ERROR: invalid EmoziString"
+ }
+ rs := []rune(es)
+ sb := strings.Builder{}
+ for i := 0; i < 校验字节数; i++ {
+ sb.WriteRune(rs[i*2])
+ }
+ sb.WriteString(string(rs[校验字节数*2:]))
+ return sb.String()
+}
+
+// IsValid 判断是否是合法 EmoziString
+func (es EmoziString) IsValid() bool {
+ rs := []rune(es)
+ if len(rs) < 校验字节数+4 {
+ return false
+ }
+ h := crc32.NewIEEE()
+ sum := uint32(0)
+ for i := 0; i < 校验字节数; i++ {
+ h.Write(base14.StringToBytes(string(rs[i*2])))
+ sum += 校验倍数[i] * uint32(逆校验表[rs[i*2+1]])
+ }
+ h.Write(base14.StringToBytes(string(rs[校验字节数*2:])))
+ return h.Sum32()%校验模 == sum
+}
diff --git a/string_test.go b/string_test.go
new file mode 100644
index 0000000..dcd97c7
--- /dev/null
+++ b/string_test.go
@@ -0,0 +1,20 @@
+package emozi
+
+import "testing"
+
+func TestWrapUnwrap(t *testing.T) {
+ t.Log(校验表长度)
+ if !WrapRawEmoziString("😨😨😨😨").IsValid() {
+ t.Fail()
+ }
+ if EmoziString("😨😨😨😨😨😨😨").IsValid() {
+ t.Fail()
+ }
+}
+
+func TestString(t *testing.T) {
+ t.Log(校验表长度)
+ if WrapRawEmoziString("😨😨😨😨").String() != "😨😨😨😨" {
+ t.Fail()
+ }
+}
diff --git a/字.db b/字.db
new file mode 100644
index 0000000000000000000000000000000000000000..5300278aa5cf5ca326a079122bfd083037d06b8e
GIT binary patch
literal 671744
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