Added cj & jyutping lookup

This commit is contained in:
2026-02-20 12:41:04 +08:00
parent 59d5934097
commit f6c9e40540
21 changed files with 114450 additions and 139 deletions

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "datasources/cjlookup/rime-cangjie"]
path = datasources/cjlookup/rime-cangjie
url = https://github.com/rime/rime-cangjie.git
[submodule "datasources/cjlookup/rime-cantonese"]
path = datasources/cjlookup/rime-cantonese
url = https://github.com/rime/rime-cantonese.git

View File

@@ -1,4 +1,4 @@
FROM golang:1.19-alpine AS build FROM golang:1.25-alpine AS build
WORKDIR /app WORKDIR /app
@@ -18,6 +18,7 @@ FROM scratch
COPY --from=alpine:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=alpine:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=build /golifehkbot / COPY --from=build /golifehkbot /
COPY "datasources/cjlookup/maps/*" /
WORKDIR / WORKDIR /
CMD [ "/golifehkbot" ] CMD [ "/golifehkbot" ]

View File

@@ -0,0 +1,45 @@
package cjlookup
import (
query "github.com/tgckpg/golifehk/query"
"strconv"
)
type CChar struct {
Face string
CangJie string
JyutPing string
TungJamZi *[]*CChar
YiDukJam *[]string
}
type CJyutPing struct {
Ref *CChar
SKey string
query.Searchable
}
type CFace struct {
Ref *CChar
query.Searchable
}
func (this *CJyutPing) Test(val string) bool {
_, err := strconv.Atoi(val)
if err == nil {
return true
}
return false
}
func (this *CFace) Test(val string) bool {
_, err := strconv.Atoi(val)
if err == nil {
return true
}
return false
}
func (m *CChar) String() string {
return m.Face
}

View File

@@ -0,0 +1,132 @@
package cjlookup
import (
"fmt"
"strconv"
"strings"
query "github.com/tgckpg/golifehk/query"
utils "github.com/tgckpg/golifehk/utils"
"golang.org/x/exp/slices"
)
type QueryResult struct {
Lang string
Error error
Query *query.QueryObject
}
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("\n")
utils.WriteMDv2Text(sb, "異讀: ")
utils.WriteMDv2Text(sb, strings.Join(*cc.YiDukJam, " "))
}
sb.WriteString("\n")
utils.WriteMDv2Text(sb, "倉: ")
utils.WriteMDv2Text(sb, cc.CangJie)
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 {
sb.WriteString(" ")
utils.WriteMDv2Text(sb, cchar.Face)
utils.WriteMDv2Text(sb, strconv.Itoa(i+1))
}
}
func (this QueryResult) Message() (string, error) {
if this.Error != nil {
return "", this.Error
}
if this.Query == nil {
panic("Query is nil")
}
sb := strings.Builder{}
q := *this.Query
argv := *q.SearchTerms
args := len(argv)
if len(*q.Results) == 0 {
terms := make([]string, args, len(*q.SearchTerms))
for i, term := range *q.SearchTerms {
terms[i] = term.Org
}
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) {
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))
}
} 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)
}
if 0 < x {
for i, entry := range *q.Results {
cjp := any(entry).(*CJyutPing)
if (i + 1) == x {
writeCCharInfo(&sb, cjp.Ref)
}
}
}
}
} else {
cjp := any((*q.Results)[0]).(*CFace)
if args == 1 {
writeCCharInfo(&sb, cjp.Ref)
} 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]
if tjz != nil {
writeCCharInfo(&sb, tjz)
}
}
}
return sb.String(), nil
}

View File

@@ -0,0 +1,4 @@
#!/bin/bash
cp ./rime-cangjie/cangjie5.dict.yaml ./maps/
cp ./rime-cantonese/jyut6ping3.chars.dict.yaml ./maps/

View File

@@ -0,0 +1,32 @@
package cjlookup
import (
"fmt"
"log"
"net/url"
"golang.org/x/text/encoding/traditionalchinese"
)
var CUHARTS_FACE = "[%s](https://humanum.arts.cuhk.edu.hk/Lexis/lexi-can/search.php?q=%s)"
var ZDIC_FACE = "[%s](https://www.zdic.net/hans/%s)"
func getCUHARTSUrlForChar(c string) string {
b, err := Big5UrlParam(c)
if err != nil {
log.Printf("Failed to encode:", c, err)
return fmt.Sprintf(ZDIC_FACE, c, c)
}
return fmt.Sprintf(CUHARTS_FACE, c, b)
}
func Big5UrlParam(input string) (string, error) {
enc := traditionalchinese.Big5.NewEncoder()
encodedBytes, err := enc.Bytes([]byte(input))
if err != nil {
return "", err
}
urlEncoded := url.PathEscape(string(encodedBytes))
return urlEncoded, nil
}

View File

@@ -0,0 +1,11 @@
package cjlookup
import (
"testing"
)
func TestCUHARTLinks(t *testing.T) {
if Big5UrlParam("呀") != "%A7r" {
t.Errorf("Faild to encode Big5 string: %A7r", err)
}
}

View File

@@ -0,0 +1,172 @@
package cjlookup
import (
"bufio"
"encoding/csv"
utils "github.com/tgckpg/golifehk/utils"
"io"
"log"
"os"
"path/filepath"
"strconv"
"strings"
)
var TXT_CANGJIE_KEYS string = filepath.Join(utils.WORKDIR, "cangjie.keys.txt")
var YAML_CANGJIE5_DICT string = filepath.Join(utils.WORKDIR, "cangjie5.dict.yaml")
var YAML_JYUTPING_CHARS string = filepath.Join(utils.WORKDIR, "jyut6ping3.chars.dict.yaml")
func ReadCangJieKeys() (*strings.Replacer, error) {
f, err := os.Open(TXT_CANGJIE_KEYS)
if err != nil {
log.Fatal(err)
}
defer f.Close()
r := csv.NewReader(f)
r.Comma = '\t'
r.FieldsPerRecord = -1
cjKeymap := []string{}
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
cjKeymap = append(cjKeymap, record[0])
cjKeymap = append(cjKeymap, record[1])
}
return strings.NewReplacer(cjKeymap...), nil
}
func ReadCangJieTable(charMap map[string]*CChar, repl *strings.Replacer) error {
f, err := os.Open(YAML_CANGJIE5_DICT)
if err != nil {
log.Fatal(err)
}
defer f.Close()
br := bufio.NewReader(f)
// Skip until YAML document end
for {
line, err := br.ReadString('\n')
if err != nil {
return err
}
if strings.TrimSpace(line) == "..." {
break
}
}
r := csv.NewReader(br)
r.Comma = '\t'
r.FieldsPerRecord = -1
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
face := record[0]
if c, ok := charMap[face]; ok {
c.Face = face
c.CangJie = repl.Replace(record[1])
} else {
c := CChar{}
c.Face = face
c.CangJie = repl.Replace(record[1])
charMap[face] = &c
}
}
return nil
}
func ReadJyutPingTable(charMap map[string]*CChar) (map[string]*[]*CChar, error) {
f, err := os.Open(YAML_JYUTPING_CHARS)
if err != nil {
log.Fatal(err)
}
defer f.Close()
br := bufio.NewReader(f)
// Skip until YAML document end
for {
line, err := br.ReadString('\n')
if err != nil {
return nil, err
}
if strings.TrimSpace(line) == "..." {
break
}
}
r := csv.NewReader(br)
r.Comma = '\t'
r.FieldsPerRecord = -1
JyutPingMap := map[string]*[]*CChar{}
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
face := record[0]
jyutping := record[1]
var c *CChar
c, ok := charMap[face]
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
}
} else {
c = &CChar{}
c.Face = face
c.JyutPing = jyutping
charMap[face] = c
}
pListPtr, ok := JyutPingMap[jyutping]
if !ok {
pList := []*CChar{}
pListPtr = &pList
JyutPingMap[jyutping] = pListPtr
}
*pListPtr = append(*pListPtr, c)
c.TungJamZi = pListPtr
}
return JyutPingMap, nil
}

View File

@@ -0,0 +1,26 @@
a 日
b 月
c 金
d 木
e 水
f 火
g 土
h 竹
i 戈
j 十
k 大
l 中
m 一
n 弓
o 人
p 心
q 手
r 口
s 尸
t 廿
u 山
v 女
w 田
x 難
y 卜
z 重

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
package cjlookup
import (
"testing"
)
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)
}
/*
for i, c := range j {
t.Log(i, c.CangJie)
}
*/
}

View File

@@ -0,0 +1,45 @@
package cjlookup
import (
"fmt"
"log"
"strings"
"github.com/tgckpg/golifehk/query"
)
func Query(lang string, message string) query.IQueryResult {
var qResults *query.QueryObject
var err error
var searchables *[]query.ISearchable
log.Printf("HNHNHNHNHNHNHNHNHNH")
qr := QueryResult{Lang: lang}
messageU := strings.ToUpper(message)
// Only look up jyut ping
if !strings.HasPrefix(messageU, "JP ") {
err = fmt.Errorf("Invalid query")
}
if err != nil {
qr.Error = err
goto qrReturn
}
messageU = messageU[3:]
searchables, err = getSearchables()
qResults, err = query.Parse(messageU, searchables)
qr.Query = qResults
if err != nil {
qr.Error = err
goto qrReturn
}
qrReturn:
var iqr query.IQueryResult
iqr = &qr
return iqr
}

View File

@@ -0,0 +1,45 @@
package cjlookup
import (
"fmt"
"strings"
"testing"
)
func TestQuery(t *testing.T) {
qo := Query("zh-Hant", "jp jyut6")
mesg, err := qo.Message()
if err != nil {
t.Errorf("Unexpected Error: %s", err)
}
if !strings.Contains(mesg, "粵42") {
t.Errorf("Expected 粵42 in response, got \"%s\" instead", mesg)
}
qo = Query("zh-Hant", "jp jyut6")
mesg, err = qo.Message()
if !strings.Contains(mesg, "粵42") {
t.Errorf("Expected 粵42 in response, got \"%s\" instead", mesg)
}
qo = Query("zh-Hant", "NaN")
mesg, err = qo.Message()
if err == nil {
t.Errorf("Expecting error, got \"%s\" instead", mesg)
}
qo = Query("zh-Hant", "jp 粵")
mesg, err = qo.Message()
if !strings.Contains(mesg, "閲62") {
t.Errorf("Expected 閲62 in response, got \"%s\" instead", mesg)
}
qo = Query("zh-Hant", "jp 粵 62")
mesg, err = qo.Message()
if !strings.Contains(mesg, "閲62") {
t.Errorf("Expected 閲62 in response, got \"%s\" instead", mesg)
}
fmt.Println(mesg)
}

View File

@@ -0,0 +1,42 @@
package cjlookup
import (
"strings"
query "github.com/tgckpg/golifehk/query"
)
func getSearchables() (*[]query.ISearchable, error) {
searchables := []query.ISearchable{}
cjRepl, err := ReadCangJieKeys()
if err != nil {
return nil, err
}
chars := map[string]*CChar{}
ReadCangJieTable(chars, cjRepl)
jpMap, err := ReadJyutPingTable(chars)
if err != nil {
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 _, c := range chars {
ccj := CFace{}
ccj.Ref = c
ccj.Key = &c.Face
searchables = append(searchables, &ccj)
}
return &searchables, nil
}

8
go.mod
View File

@@ -1,5 +1,9 @@
module github.com/tgckpg/golifehk module github.com/tgckpg/golifehk
go 1.19 go 1.25.0
require github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 // indirect require (
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa
golang.org/x/text v0.34.0
)

4
go.sum
View File

@@ -1,2 +1,6 @@
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=

119
main.go
View File

@@ -1,78 +1,81 @@
package main package main
import ( import (
"fmt" "fmt"
"log" "log"
"os" "os"
utils "github.com/tgckpg/golifehk/utils"
mtrbus "github.com/tgckpg/golifehk/datasources/mtr/bus" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
kmb "github.com/tgckpg/golifehk/datasources/kmb" cjlookup "github.com/tgckpg/golifehk/datasources/cjlookup"
query "github.com/tgckpg/golifehk/query" kmb "github.com/tgckpg/golifehk/datasources/kmb"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" mtrbus "github.com/tgckpg/golifehk/datasources/mtr/bus"
query "github.com/tgckpg/golifehk/query"
utils "github.com/tgckpg/golifehk/utils"
) )
func botsend( bot *tgbotapi.BotAPI, update *tgbotapi.Update, mesg *string ) { func botsend(bot *tgbotapi.BotAPI, update *tgbotapi.Update, mesg *string) {
var msg tgbotapi.MessageConfig var msg tgbotapi.MessageConfig
msg = tgbotapi.NewMessage( update.Message.Chat.ID, *mesg ) msg = tgbotapi.NewMessage(update.Message.Chat.ID, *mesg)
msg.ParseMode = "MarkdownV2" msg.ParseMode = "MarkdownV2"
msg.ReplyToMessageID = update.Message.MessageID msg.ReplyToMessageID = update.Message.MessageID
bot.Send( msg ) bot.Send(msg)
} }
func main() { func main() {
bot, err := tgbotapi.NewBotAPI( os.Getenv( "TELEGRAM_API_TOKEN" ) ) bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_API_TOKEN"))
if err != nil { if err != nil {
log.Panic( err ) log.Panic(err)
} }
bot.Debug = true bot.Debug = true
log.Printf("Authorized on account %s", bot.Self.UserName) log.Printf("Authorized on account %s", bot.Self.UserName)
u := tgbotapi.NewUpdate(0) u := tgbotapi.NewUpdate(0)
u.Timeout = 60 u.Timeout = 60
updates := bot.GetUpdatesChan(u) updates := bot.GetUpdatesChan(u)
for update := range updates { for update := range updates {
if update.Message == nil { if update.Message == nil {
continue continue
} }
log.Printf( "[%s] %s", update.Message.From.UserName, update.Message.Text ) log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
isGroup := ( update.Message.Chat.ID < 0 ) isGroup := (update.Message.Chat.ID < 0)
mesg, processed := utils.SystemControl( update.Message ) mesg, processed := utils.SystemControl(update.Message)
if processed { if processed {
if mesg != "" { if mesg != "" {
botsend( bot, &update, &mesg ) botsend(bot, &update, &mesg)
} }
continue continue
} }
f_queries := []func( string, string ) query.IQueryResult{ f_queries := []func(string, string) query.IQueryResult{
mtrbus.Query, cjlookup.Query,
kmb.Query, mtrbus.Query,
} kmb.Query,
}
var f_sent bool = false var f_sent bool = false
var f_err error = nil var f_err error = nil
for _, Query := range f_queries { for _, Query := range f_queries {
var err error var err error
mesg, err = Query( "zh-Hant", update.Message.Text ).Message() mesg, err = Query("zh-Hant", update.Message.Text).Message()
if err == nil { if err == nil {
f_sent = true f_sent = true
botsend( bot, &update, &mesg ) botsend(bot, &update, &mesg)
} else if f_err == nil { } else if f_err == nil {
f_err = err f_err = err
} }
} }
if !isGroup && !f_sent && f_err != nil { if !isGroup && !f_sent && f_err != nil {
mesg := utils.MDv2Text( fmt.Sprintf( "%s", f_err ) ) mesg := utils.MDv2Text(fmt.Sprintf("%s", f_err))
botsend( bot, &update, &mesg ) botsend(bot, &update, &mesg)
} }
} }
} }

View File

@@ -1,95 +1,119 @@
package utils package utils
import ( import (
"bytes" "bytes"
"os" "os"
"strconv" "strconv"
"strings" "strings"
) )
var MARKDOWN_ESC []string = []string{"_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"} var MARKDOWN_ESC []string = []string{"_", "*", "[", "]", "(", ")", "~", "`", ">", "#", "+", "-", "=", "|", "{", "}", ".", "!"}
func WriteMDv2Text( sb *strings.Builder, t string ) { func Contains[T comparable](slice []T, target T) bool {
for _, c := range MARKDOWN_ESC { for _, v := range slice {
t = strings.Replace( t, c, "\\" + c, -1 ) if v == target {
} return true
}
sb.WriteString( t ) }
return false
} }
func MDv2Text( t string ) string { func WriteMDv2Text(sb *strings.Builder, t string) {
sb := strings.Builder{} for _, c := range MARKDOWN_ESC {
t = strings.Replace(t, c, "\\"+c, -1)
}
for _, c := range MARKDOWN_ESC { sb.WriteString(t)
t = strings.Replace( t, c, "\\" + c, -1 )
}
sb.WriteString( t )
return sb.String()
} }
func ToPower( t string ) string { func MDv2Text(t string) string {
for s, r := range POWER_NUMBERS { sb := strings.Builder{}
t = strings.ReplaceAll( t, s, r )
} for _, c := range MARKDOWN_ESC {
return t t = strings.Replace(t, c, "\\"+c, -1)
}
sb.WriteString(t)
return sb.String()
} }
func ReadBOM( buff *bytes.Buffer ) { func IsASCIIAlnum(s string) bool {
b, _ := buff.ReadByte() if s == "" {
if b != 0xef { return false
buff.UnreadByte() }
return for i := 0; i < len(s); i++ {
} c := s[i]
b, _ = buff.ReadByte() if !(c >= '0' && c <= '9' ||
if b != 0xbb { c >= 'A' && c <= 'Z' ||
buff.UnreadByte() c >= 'a' && c <= 'z') {
buff.UnreadByte() return false
return }
} }
b, _ = buff.ReadByte() return true
if b != 0xbf {
buff.UnreadByte()
buff.UnreadByte()
buff.UnreadByte()
}
} }
func TryGetEnv[T any]( name string, fallback T ) T { func ToPower(t string) string {
v := os.Getenv( name ) for s, r := range POWER_NUMBERS {
t = strings.ReplaceAll(t, s, r)
if v != "" { }
switch any( fallback ).(type) { return t
case uint64: }
p, err := strconv.ParseUint( v, 10, 64 )
if err == nil { func ReadBOM(buff *bytes.Buffer) {
return any( uint64( p ) ).(T) b, _ := buff.ReadByte()
} if b != 0xef {
case uint32: buff.UnreadByte()
p, err := strconv.ParseUint( v, 10, 32 ) return
if err == nil { }
return any( uint32( p ) ).(T) b, _ = buff.ReadByte()
} if b != 0xbb {
case int: buff.UnreadByte()
p, err := strconv.ParseInt( v, 10, 32 ) buff.UnreadByte()
if err == nil { return
return any( int( p ) ).(T) }
} b, _ = buff.ReadByte()
case float64: if b != 0xbf {
p, err := strconv.ParseFloat( v, 64 ) buff.UnreadByte()
if err == nil { buff.UnreadByte()
return any( float64( p ) ).(T) buff.UnreadByte()
} }
case float32: }
p, err := strconv.ParseFloat( v, 32 )
if err == nil { func TryGetEnv[T any](name string, fallback T) T {
return any( float32( p ) ).(T) v := os.Getenv(name)
}
default: if v != "" {
return any( v ).(T) switch any(fallback).(type) {
} case uint64:
p, err := strconv.ParseUint(v, 10, 64)
} if err == nil {
return any(uint64(p)).(T)
return fallback }
case uint32:
p, err := strconv.ParseUint(v, 10, 32)
if err == nil {
return any(uint32(p)).(T)
}
case int:
p, err := strconv.ParseInt(v, 10, 32)
if err == nil {
return any(int(p)).(T)
}
case float64:
p, err := strconv.ParseFloat(v, 64)
if err == nil {
return any(float64(p)).(T)
}
case float32:
p, err := strconv.ParseFloat(v, 32)
if err == nil {
return any(float32(p)).(T)
}
default:
return any(v).(T)
}
}
return fallback
} }