commit d54f106dee225e40824f6b49b4b49c06f15d2fe1
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-02-20T13:06:47Z |
| subject | Rewrite some struct linkages |
commit d54f106dee225e40824f6b49b4b49c06f15d2fe1
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-02-20T13:06:47Z
Rewrite some struct linkages
---
datasources/cjlookup/CChar.go | 57 +++++++++++---
datasources/cjlookup/QueryResult.go | 70 ++++++-----------
datasources/cjlookup/humanumarts.go | 49 +++++++++++-
datasources/cjlookup/humanumarts_test.go | 7 +-
datasources/cjlookup/maps.go | 88 +++++++++++++++-------
.../cjlookup/maps/jyut6ping3.chars.dict.yaml | 2 +-
datasources/cjlookup/objects_test.go | 28 +++----
datasources/cjlookup/query_test.go | 13 +++-
datasources/cjlookup/rime-cantonese | 2 +-
datasources/cjlookup/searchables.go | 24 +++---
10 files changed, 220 insertions(+), 120 deletions(-)
diff --git a/datasources/cjlookup/CChar.go b/datasources/cjlookup/CChar.go
index 2e7c0cd..4898051 100644
--- a/datasources/cjlookup/CChar.go
+++ b/datasources/cjlookup/CChar.go
@@ -2,25 +2,29 @@ package cjlookup
import (
query "github.com/tgckpg/golifehk/query"
+ "golang.org/x/exp/slices"
"strconv"
)
type CChar struct {
Face string
CangJie string
- JyutPing string
- TungJamZi *[]*CChar
- YiDukJam *[]string
+ JyutPing *CJyutPing
+ DukJam *[]*DukJam
+ _JiDukJam *[]*CJyutPing
+ query.Searchable
}
-type CJyutPing struct {
- Ref *CChar
- SKey string
- query.Searchable
+type DukJam struct {
+ Weight int
+ JyutPing *CJyutPing
}
-type CFace struct {
- Ref *CChar
+type CJyutPing struct {
+ Roman string
+ SearchKey string // Searchable key
+ TungJamZi *[]*CChar
+ tSorted bool
query.Searchable
}
@@ -32,7 +36,7 @@ func (this *CJyutPing) Test(val string) bool {
return false
}
-func (this *CFace) Test(val string) bool {
+func (this *CChar) Test(val string) bool {
_, err := strconv.Atoi(val)
if err == nil {
return true
@@ -40,6 +44,35 @@ func (this *CFace) Test(val string) bool {
return false
}
-func (m *CChar) String() string {
- return m.Face
+func (this *CChar) JiDukJam() *[]*CJyutPing {
+ if this._JiDukJam == nil {
+ jdj := &[]*CJyutPing{}
+ for _, dj := range *this.DukJam {
+ if dj.JyutPing != this.JyutPing {
+ *jdj = append(*jdj, dj.JyutPing)
+ }
+ }
+ this._JiDukJam = jdj
+ }
+
+ return this._JiDukJam
+}
+
+func (this *CJyutPing) SortedTungJamZi() *[]*CChar {
+ if this.tSorted {
+ return this.TungJamZi
+ }
+
+ slices.SortFunc(*this.TungJamZi, func(a, b *CChar) int {
+ switch {
+ case a.Face < b.Face:
+ return -1
+ case a.Face > b.Face:
+ return 1
+ default:
+ return 0
+ }
+ })
+
+ return this.TungJamZi
}
diff --git a/datasources/cjlookup/QueryResult.go b/datasources/cjlookup/QueryResult.go
index fac6df2..a824bbc 100644
--- a/datasources/cjlookup/QueryResult.go
+++ b/datasources/cjlookup/QueryResult.go
@@ -7,7 +7,6 @@ import (
query "github.com/tgckpg/golifehk/query"
utils "github.com/tgckpg/golifehk/utils"
- "golang.org/x/exp/slices"
)
type QueryResult struct {
@@ -19,11 +18,11 @@ type QueryResult struct {
func writeCCharInfo(sb *strings.Builder, cc *CChar) {
sb.WriteString(getCUHARTSUrlForChar(cc.Face))
sb.WriteString(" ")
- utils.WriteMDv2Text(sb, cc.JyutPing)
- if cc.YiDukJam != nil {
+ sb.WriteString(getCUHARTSUrlForPronounce(cc.JyutPing.Roman))
+ if 0 < len(*cc.JiDukJam()) {
sb.WriteString("\n")
utils.WriteMDv2Text(sb, "異讀: ")
- utils.WriteMDv2Text(sb, strings.Join(*cc.YiDukJam, " "))
+ sb.WriteString(strings.Join(getCUHARTSUrlsForPronounce(*cc.JiDukJam()), " "))
}
sb.WriteString("\n")
utils.WriteMDv2Text(sb, "倉: ")
@@ -31,18 +30,7 @@ func writeCCharInfo(sb *strings.Builder, cc *CChar) {
sb.WriteString("\n")
utils.WriteMDv2Text(sb, "同音字:")
- slices.SortFunc(*cc.TungJamZi, func(a, b *CChar) int {
- switch {
- case a.Face < b.Face:
- return -1
- case a.Face > b.Face:
- return 1
- default:
- return 0
- }
- })
-
- for i, cchar := range *cc.TungJamZi {
+ for i, cchar := range *cc.JyutPing.SortedTungJamZi() {
sb.WriteString(" ")
utils.WriteMDv2Text(sb, cchar.Face)
utils.WriteMDv2Text(sb, strconv.Itoa(i+1))
@@ -74,26 +62,24 @@ func (this QueryResult) Message() (string, error) {
return "", fmt.Errorf("Not Found: \"%s\"", strings.Join(terms, "\", \""))
}
- slices.SortFunc(*q.Results, func(a, b query.ISearchable) int {
- aa := a.(*CJyutPing)
- bb := b.(*CJyutPing)
- switch {
- case aa.Ref.Face < bb.Ref.Face:
- return -1
- case aa.Ref.Face > bb.Ref.Face:
- return 1
- default:
- return 0
- }
- })
-
if utils.IsASCIIAlnum(argv[0].Value) {
+ // Roman Search
+ cjp := any((*q.Results)[0]).(*CJyutPing)
if args == 1 {
- for i, entry := range *q.Results {
- cjp := any(entry).(*CJyutPing)
- sb.WriteString(" ")
- utils.WriteMDv2Text(&sb, cjp.Ref.Face)
- utils.WriteMDv2Text(&sb, strconv.Itoa(i+1))
+ if len(*q.Results) == 1 {
+ if len(*cjp.SortedTungJamZi()) == 1 {
+ for _, cchar := range *cjp.SortedTungJamZi() {
+ writeCCharInfo(&sb, cchar)
+ }
+ } else {
+ for i, cchar := range *cjp.SortedTungJamZi() {
+ sb.WriteString(" ")
+ utils.WriteMDv2Text(&sb, cchar.Face)
+ utils.WriteMDv2Text(&sb, strconv.Itoa(i+1))
+ }
+ }
+ } else {
+ return "", fmt.Errorf("Multiple results found: %s", *q.Results)
}
} else if args == 2 {
var err error
@@ -101,26 +87,20 @@ func (this QueryResult) Message() (string, error) {
if err != nil {
return "", fmt.Errorf("Invalid index: %s", argv[1].Org)
}
- if 0 < x {
- for i, entry := range *q.Results {
- cjp := any(entry).(*CJyutPing)
- if (i + 1) == x {
- writeCCharInfo(&sb, cjp.Ref)
- }
- }
- }
+ writeCCharInfo(&sb, (*cjp.SortedTungJamZi())[x-1])
}
} else {
- cjp := any((*q.Results)[0]).(*CFace)
+ // Char Search
+ cchar := any((*q.Results)[0]).(*CChar)
if args == 1 {
- writeCCharInfo(&sb, cjp.Ref)
+ writeCCharInfo(&sb, cchar)
} else if args == 2 {
var err error
x, err := strconv.Atoi(argv[1].Value)
if err != nil {
return "", fmt.Errorf("Invalid index: %s", argv[1].Org)
}
- tjz := (*(*cjp.Ref).TungJamZi)[x-1]
+ tjz := (*(cchar.JyutPing).SortedTungJamZi())[x-1]
if tjz != nil {
writeCCharInfo(&sb, tjz)
diff --git a/datasources/cjlookup/humanumarts.go b/datasources/cjlookup/humanumarts.go
index 520c1de..dc484c8 100644
--- a/datasources/cjlookup/humanumarts.go
+++ b/datasources/cjlookup/humanumarts.go
@@ -4,22 +4,69 @@ import (
"fmt"
"log"
"net/url"
+ "strings"
"golang.org/x/text/encoding/traditionalchinese"
)
var CUHARTS_FACE = "[%s](https://humanum.arts.cuhk.edu.hk/Lexis/lexi-can/search.php?q=%s)"
+var CUHARTS_PHO = "[%s](https://humanum.arts.cuhk.edu.hk/Lexis/lexi-can/pho-rel.php?%s&classified=classified.php?st=0)"
var ZDIC_FACE = "[%s](https://www.zdic.net/hans/%s)"
+var SING_MOU_S1 = []string{"b", "c", "d", "f", "g", "gw", "h", "j", "k", "kw", "l", "m", "n", "ng", "p", "s", "t", "w", "z"}
+var WAN_MOU_S2 = []string{"aa", "aai", "aau", "aam", "aan", "aang", "aap", "aat", "aak", "ai", "au", "am", "an", "ang", "ap", "at", "ak", "e", "ei", "eu", "em", "eng", "ep", "ek", "i", "iu", "im", "in", "ing", "ip", "it", "ik", "o", "oi", "ou", "on", "ong", "ot", "ok", "oe", "oeng", "oek", "eoi", "eon", "eot", "u", "ui", "un", "ung", "ut", "uk", "yu", "yun", "yut", "m", "ng"}
+var SING_DIU_S3 = []string{"1", "2", "3", "4", "5", "6"}
func getCUHARTSUrlForChar(c string) string {
b, err := Big5UrlParam(c)
if err != nil {
- log.Printf("Failed to encode:", c, err)
+ log.Print("Failed to encode:", c, err)
return fmt.Sprintf(ZDIC_FACE, c, c)
}
return fmt.Sprintf(CUHARTS_FACE, c, b)
}
+func SParams(p string) string {
+ s1 := "-"
+ for _, x := range SING_MOU_S1 {
+ if strings.HasPrefix(p, x) {
+ s1 = x
+ break
+ }
+ }
+
+ s3 := "-"
+ for _, x := range SING_DIU_S3 {
+ if strings.HasSuffix(p, x) {
+ s3 = x
+ break
+ }
+ }
+
+ s2 := ""
+ bestMatch := 0
+ for _, x := range WAN_MOU_S2 {
+ if strings.HasSuffix(strings.TrimSuffix(strings.TrimPrefix(p, s1), s3), x) {
+ if bestMatch < len(x) {
+ s2 = x
+ bestMatch = len(x)
+ }
+ }
+ }
+ return fmt.Sprintf("s1=%s&s2=%s&s3=%s", s1, s2, s3)
+}
+
+func getCUHARTSUrlsForPronounce(p []*CJyutPing) []string {
+ urls := []string{}
+ for _, x := range p {
+ urls = append(urls, getCUHARTSUrlForPronounce(x.Roman))
+ }
+ return urls
+}
+
+func getCUHARTSUrlForPronounce(p string) string {
+ return fmt.Sprintf(CUHARTS_PHO, p, SParams(p))
+}
+
func Big5UrlParam(input string) (string, error) {
enc := traditionalchinese.Big5.NewEncoder()
encodedBytes, err := enc.Bytes([]byte(input))
diff --git a/datasources/cjlookup/humanumarts_test.go b/datasources/cjlookup/humanumarts_test.go
index 34a64a6..4cc6f48 100644
--- a/datasources/cjlookup/humanumarts_test.go
+++ b/datasources/cjlookup/humanumarts_test.go
@@ -5,7 +5,12 @@ import (
)
func TestCUHARTLinks(t *testing.T) {
- if Big5UrlParam("呀") != "%A7r" {
+ s, err := Big5UrlParam("呀")
+ if s != "%A7r" {
t.Errorf("Faild to encode Big5 string: %A7r", err)
}
+
+ if SParams("caang4") != "s1=c&s2=aang&s3=4" {
+ t.Error("Faild to parse s params for: caang4")
+ }
}
diff --git a/datasources/cjlookup/maps.go b/datasources/cjlookup/maps.go
index 1a2d90f..82d8345 100644
--- a/datasources/cjlookup/maps.go
+++ b/datasources/cjlookup/maps.go
@@ -86,6 +86,7 @@ func ReadCangJieTable(charMap map[string]*CChar, repl *strings.Replacer) error {
} else {
c := CChar{}
c.Face = face
+ c.Key = &c.Face
c.CangJie = repl.Replace(record[1])
charMap[face] = &c
}
@@ -94,7 +95,7 @@ func ReadCangJieTable(charMap map[string]*CChar, repl *strings.Replacer) error {
return nil
}
-func ReadJyutPingTable(charMap map[string]*CChar) (map[string]*[]*CChar, error) {
+func ReadJyutPingTable(charMap map[string]*CChar) (map[string]*CJyutPing, error) {
f, err := os.Open(YAML_JYUTPING_CHARS)
if err != nil {
log.Fatal(err)
@@ -118,7 +119,7 @@ func ReadJyutPingTable(charMap map[string]*CChar) (map[string]*[]*CChar, error)
r.Comma = '\t'
r.FieldsPerRecord = -1
- JyutPingMap := map[string]*[]*CChar{}
+ JyutPingMap := map[string]*CJyutPing{}
for {
record, err := r.Read()
if err == io.EOF {
@@ -131,41 +132,70 @@ func ReadJyutPingTable(charMap map[string]*CChar) (map[string]*[]*CChar, error)
face := record[0]
jyutping := record[1]
- var c *CChar
- c, ok := charMap[face]
+ var tjz *[]*CChar
+ cjp, ok := JyutPingMap[jyutping]
if ok {
- if len(record) == 2 {
- c.JyutPing = record[1]
- } else if len(record) == 3 {
- s := record[2]
- if strings.HasSuffix(s, "%") {
- _, err := strconv.Atoi(s[:len(s)-1])
- if err != nil {
- return nil, err
- }
- }
- yList := c.YiDukJam
- if yList == nil {
- yList = &[]string{}
- }
- *yList = append(*yList, record[1])
- c.YiDukJam = yList
- }
+ tjz = cjp.TungJamZi
} else {
+ cjp = &CJyutPing{}
+ cjp.Roman = jyutping
+ cjp.SearchKey = strings.ToUpper(jyutping)
+ cjp.Key = &cjp.SearchKey
+ tjz = &[]*CChar{}
+ cjp.TungJamZi = tjz
+ JyutPingMap[jyutping] = cjp
+ }
+
+ var c *CChar
+ c, ok = charMap[face]
+ if !ok {
c = &CChar{}
c.Face = face
- c.JyutPing = jyutping
+ c.Key = &c.Face
charMap[face] = c
}
- pListPtr, ok := JyutPingMap[jyutping]
- if !ok {
- pList := []*CChar{}
- pListPtr = &pList
- JyutPingMap[jyutping] = pListPtr
+ *tjz = append(*tjz, c)
+
+ var dj *DukJam
+
+ if len(record) == 2 {
+ c.JyutPing = cjp
+ dj = &DukJam{}
+ dj.Weight = 100
+ dj.JyutPing = cjp
+ } else if len(record) == 3 {
+ s := record[2]
+ var w int
+ if strings.HasSuffix(s, "%") {
+ w, err = strconv.Atoi(s[:len(s)-1])
+ if err != nil {
+ return nil, err
+ }
+ }
+ dj = &DukJam{}
+ dj.Weight = w
+ dj.JyutPing = cjp
+ }
+
+ if dj != nil {
+ if c.DukJam == nil {
+ c.DukJam = &[]*DukJam{}
+ }
+ *c.DukJam = append(*c.DukJam, dj)
+ }
+ }
+
+ for _, c := range charMap {
+ if c.JyutPing == nil && c.DukJam != nil {
+ _max := -1
+ for _, dj := range *c.DukJam {
+ if _max < dj.Weight {
+ _max = dj.Weight
+ c.JyutPing = dj.JyutPing
+ }
+ }
}
- *pListPtr = append(*pListPtr, c)
- c.TungJamZi = pListPtr
}
return JyutPingMap, nil
diff --git a/datasources/cjlookup/maps/jyut6ping3.chars.dict.yaml b/datasources/cjlookup/maps/jyut6ping3.chars.dict.yaml
index d83f195..cb87409 100644
--- a/datasources/cjlookup/maps/jyut6ping3.chars.dict.yaml
+++ b/datasources/cjlookup/maps/jyut6ping3.chars.dict.yaml
@@ -7,7 +7,7 @@
---
name: jyut6ping3.chars
-version: "2025.11.27"
+version: "2025.12.24"
sort: by_weight
...
diff --git a/datasources/cjlookup/objects_test.go b/datasources/cjlookup/objects_test.go
index 7d02137..d28e9f1 100644
--- a/datasources/cjlookup/objects_test.go
+++ b/datasources/cjlookup/objects_test.go
@@ -5,21 +5,21 @@ import (
)
func TestDataRead(t *testing.T) {
- chars := map[string]*CChar{}
- cjRepl, err := ReadCangJieKeys()
- if err != nil {
- t.Error(err)
- }
- ReadCangJieTable(chars, cjRepl)
- JyutPingMap, err := ReadJyutPingTable(chars)
- if err != nil {
- t.Error(err)
- }
- j := *JyutPingMap["sing4"]
- if j[0].TungJamZi != j[1].TungJamZi {
- t.Errorf("%s & %s does not point to the same reference.", j[0].Face, j[1].Face)
- }
/*
+ chars := map[string]*CChar{}
+ cjRepl, err := ReadCangJieKeys()
+ if err != nil {
+ t.Error(err)
+ }
+ ReadCangJieTable(chars, cjRepl)
+ JyutPingMap, err := ReadJyutPingTable(chars)
+ if err != nil {
+ t.Error(err)
+ }
+ j := *JyutPingMap["sing4"]
+ if j.TungJamZi[0].JyutPing != j.TungJamZi[1].JyutPing {
+ t.Errorf("%s & %s does not point to the same reference.", j[0].Face, j[1].Face)
+ }
for i, c := range j {
t.Log(i, c.CangJie)
}
diff --git a/datasources/cjlookup/query_test.go b/datasources/cjlookup/query_test.go
index b48338c..5dedb85 100644
--- a/datasources/cjlookup/query_test.go
+++ b/datasources/cjlookup/query_test.go
@@ -1,7 +1,6 @@
package cjlookup
import (
- "fmt"
"strings"
"testing"
)
@@ -41,5 +40,15 @@ func TestQuery(t *testing.T) {
t.Errorf("Expected 閲62 in response, got \"%s\" instead", mesg)
}
- fmt.Println(mesg)
+ qo = Query("zh-Hant", "jp jeng4 1")
+ mesg, err = qo.Message()
+ if strings.Contains(mesg, "同音字") {
+ t.Error("Unexpected TungJamZi for jeng4")
+ }
+
+ qo = Query("zh-Hant", "jp 數")
+ mesg, err = qo.Message()
+ if !strings.Contains(mesg, "異讀: [cuk1]") {
+ t.Error("Expecting 異讀 from 數")
+ }
}
diff --git a/datasources/cjlookup/rime-cantonese b/datasources/cjlookup/rime-cantonese
index 77776c0..ce0be9e 160000
--- a/datasources/cjlookup/rime-cantonese
+++ b/datasources/cjlookup/rime-cantonese
@@ -1 +1 @@
-Subproject commit 77776c0aad31c78ba743877780fae26f8b1e0dbe
+Subproject commit ce0be9ee5d7e92a0bd82c6b41e80a51190a4fd22
diff --git a/datasources/cjlookup/searchables.go b/datasources/cjlookup/searchables.go
index f7baa7a..db0adf7 100644
--- a/datasources/cjlookup/searchables.go
+++ b/datasources/cjlookup/searchables.go
@@ -1,9 +1,8 @@
package cjlookup
import (
- "strings"
-
query "github.com/tgckpg/golifehk/query"
+ "log"
)
func getSearchables() (*[]query.ISearchable, error) {
@@ -21,21 +20,18 @@ func getSearchables() (*[]query.ISearchable, error) {
return nil, err
}
- for jyutping, chars := range jpMap {
- for _, c := range *chars {
- cjp := CJyutPing{}
- cjp.Ref = c
- cjp.SKey = strings.ToUpper(jyutping)
- cjp.Key = &cjp.SKey
- searchables = append(searchables, &cjp)
+ for _, x := range jpMap {
+ if x.Key == nil {
+ log.Fatal("getSearchables CJP: ", x)
}
+ searchables = append(searchables, x)
}
- for _, c := range chars {
- ccj := CFace{}
- ccj.Ref = c
- ccj.Key = &c.Face
- searchables = append(searchables, &ccj)
+ for _, x := range chars {
+ if x.Key == nil {
+ log.Fatal("getSearchables CChar: ", x)
+ }
+ searchables = append(searchables, x)
}
return &searchables, nil