昨天把網頁載好,不過裡面的資料似乎很難處理。後來有找到另一個 API :
https://www.moedict.tw/a/字.json
它會回傳 JSON 格式的字串,解析簡單很多。而 YAML 套件也能解析 JSON ,直接上吧!
首先先把 URL 改掉:
const (
dictionary = `https://www.moedict.tw/a/%s.json`
)
呼叫改使用 fmt.Sprintf()
:
req := goreq.Request{
Uri: fmt.Sprintf(dictionary, string(word)),
}
這樣執行應該回傳就會變成 JSON 格式了。
下一步是要把 JSON 轉成 go 的資料型態,這次的結構就很鬆散了,改用 Map 做會比較簡單:
type MoeDict struct {
Heteronyms []Heteronym
}
type Heteronym struct {
Definitions []string
}
func convertJsonToStruct(json string) (dict MoeDict, err error) {
m := make(map[interface{}]interface{})
yaml.Unmarshal([]byte(json), &m)
heteronyms := convertHeteronyms(m["h"])
return MoeDict{heteronyms}, err
}
func convertSliceMap(sliceMap []interface{}) (sm []map[interface{}]interface{}) {
for _, m := range sliceMap {
sm = append(sm, m.(map[interface{}]interface{}))
}
return sm
}
func convertHeteronyms(in interface{}) (out []Heteronym) {
heteronyms := convertSliceMap(in.([]interface{}))
for _, heteronym := range heteronyms {
definitions := convertDefinitions(heteronym["d"])
out = append(out, Heteronym{
definitions,
})
}
return
}
func convertDefinitions(in interface{}) (out []string) {
definitions := convertSliceMap(in.([]interface{}))
for _, definition := range definitions {
def := convertDef(definition["f"].(string))
out = append(out, def)
}
return
}
func convertDef(in string) string {
def := in
def = strings.Replace(def, "~", "", -1)
def = strings.Replace(def, "`", "", -1)
return def
}
因為原始資料的設計是多讀音配多種解釋,會是樹狀結構加一堆陣列,所以必須要很多 for
來處理。
而 QueryCommand 改寫成這樣:
dict, err := provider.Query(str)
for _, heteronym := range dict.Heteronyms {
for _, definition := range heteronym.Definitions {
fmt.Println(definition)
}
}
$ go run main.go query 萌
草木初生的芽。
事物發生的開端或徵兆。
人民。
姓。如五代時蜀有萌慮。
發芽。
發生。
目前沒把讀音做篩選,不過這樣也感覺蠻有樣子了。
程式碼可以參考 PR Day 22