Go语言项目实战:基于开源数据的成语查询

栏目: Go · 发布时间: 7年前

内容简介:版权声明:本文为博主尹成联系QQ77025077,微信18510341407原创文章,欢迎转载侵权不究。 https://blog.csdn.net/yincheng01/article/details/84134007

版权声明:本文为博主尹成联系QQ77025077,微信18510341407原创文章,欢迎转载侵权不究。 https://blog.csdn.net/yincheng01/article/details/84134007

业务需求

  • 命令行键入一行诗句启动应用:idiom.exe -cmd start -poem 大王派我来巡山
  • 将诗句中的每个字丢入【模糊查询管道】
  • 另外再建立【精确查询管道】和【结束管道】,分别存储【成语】(大鹏展翅、占山为王、龟派气功…)和【结束指令】(fuckoff)
  • 时钟每秒随机读入一条管道数据:
    如果是【模糊查询管道】:起协程进行模糊查询,并汇总数据在内存
    如果是【精确查询管道】:起协程进行精确查询,并汇总数据在内存
    如果是【结束指令】:停止查询,将内存中的数据持久化为json并退出;

命令行参数获取工具

import (
	"fmt"
	"flag"
)

/*
argInfos	要获取的命令行参数们		例如:[3]interface{}{"cmd","默认命令","要执行的命令"}
retValuesMap	以map的形式返回用户在命令行输入的值 	[cmd:getmoney amount:666 to:张三]
*/
func GetCmdlineArgs(argInfos ...[3]interface{}) (retValuesMap map[string]interface{}) {

	fmt.Printf("type=%T,value=%v\n", argInfos, argInfos)

	//初始化返回结果
	retValuesMap = map[string]interface{}{}

	//预定义【用户可能输入的各种类型的指针】
	var strValuePtr *string
	var intValuePtr *int

	//预定义【用户可能输入的各种类型的指针】的容器
	//用户可能输入好几个string型的参数值,存放在好几个string型的指针中,将这些同种类型的指针放在同种类型的map中
	//例如:flag.Parse()了以后,可以根据【strValuePtrsMap["cmd"]】拿到【存放"cmd"值的指针】
	var strValuePtrsMap = map[string]*string{}
	var intValuePtrsMap = map[string]*int{}

	/*	var floatValuePtr *float32
		var floatValuePtrsMap []*float32
		var boolValuePtr *bool
		var boolValuePtrsMap []*bool*/

	//遍历用户需要接受的所有命令定义
	for _, argArray := range argInfos {

		/*
		先把每个命令的名称和用法拿出来,
		这俩货都是string类型的,所有都可以通过argArray[i].(string)轻松愉快地获得其字符串
		一个叫“cmd”,一个叫“你想干嘛”
		"cmd"一会会用作map的key
		*/
		//[3]interface{}
		//["cmd" "未知类型" "你想干嘛"]
		//["gid"     0     "要查询的商品ID"]
		//上面的破玩意类型[string 可能是任意类型 string]
		nameValue := argArray[0].(string)  //拿到第一个元素的string值,是命令的name
		usageValue := argArray[2].(string) //拿到最后一个元素的string值,是命令的usage

		//判断argArray[1]的具体类型
		switch argArray[1].(type) {
		case string:
			//得到【存放cmd的指针】,cmd的值将在flag.Parse()以后才会有
			//cmdValuePtr = flag.String("cmd", argArray[1].(string), "你想干嘛")
			strValuePtr = flag.String(nameValue, argArray[1].(string), usageValue)

			//将这个破指针以"cmd"为键,存在【专门放置string型指针的map,即strValuePtrsMap】中
			strValuePtrsMap[nameValue] = strValuePtr

		case int:
			//得到【存放gid的指针】,gid的值将在flag.Parse()以后才会有
			//gidValuePtr = flag.String("gid", argArray[1].(int), "商品ID")
			intValuePtr = flag.Int(nameValue, argArray[1].(int), usageValue)

			//将这个破指针以"gid"为键,存在【专门放置int型指针的map,即intValuePtrsMap】中
			intValuePtrsMap[nameValue] = intValuePtr
		}

	}

	/*
	程序运行到这里,所有不同类型的【存值指针】都放在对相应类型的map中了
	flag.Parse()了以后,可以从map中以参数名字获取出【存值指针】,进而获得【用户输入的值】
	*/

	//用户输入完了,解析,【用户输入的值】全都放在对应的【存值指针】中
	flag.Parse()

	/*
	遍历各种可能类型的【存值指针的map】
	*/
	if len(strValuePtrsMap) > 0 {
		//从【cmd存值指针的map】中拿取cmd的值,还以cmd为键存入结果map中
		for k, vPtr := range strValuePtrsMap {
			retValuesMap[k] = *vPtr
		}
	}
	if len(intValuePtrsMap) > 0 {
		//从【gid存值指针的map】中拿取gid的值,还以gid为键存入结果map中
		for k, vPtr := range intValuePtrsMap {
			retValuesMap[k] = *vPtr
		}
	}

	//返回结果map
	return
}

定义成语数据模型

import "fmt"

//成语
type Idiom struct {
	Title      string
	Spell      string
	Content    string
	Sample     string
	Derivation string
}

//打印成语数据
func PrintIdiom(idiom Idiom) {
	if idiom.Title != "" {
		fmt.Printf("Title:%s\n", idiom.Title)
		fmt.Printf("Spell:%s\n", idiom.Spell)
		fmt.Printf("Sample:%s\n", idiom.Sample)
		fmt.Printf("Derivation:%s\n", idiom.Derivation)
		fmt.Printf("Content:%s\n", idiom.Content)
	} else {
		fmt.Println("未找到成语!")
	}
}

定义成语数据模型和JSON的互化工具

import (
	"encoding/json"
	"os"
	"fmt"
)

//将模糊查询的json转化为 go 数据
func ParseJson2Idioms(jsonStr string) (idiomsMap map[string]Idiom) {
	idiomsMap = make(map[string]Idiom)

	//将json转换为go数据
	tempMap := make(map[string]interface{})
	json.Unmarshal([]byte(jsonStr), &tempMap)
	//fmt.Println(tempMap)
	dataSlice := tempMap["showapi_res_body"].(map[string]interface{})["data"].([]interface{})
	//fmt.Printf("type=%T,value=%v",dataSlice,dataSlice)
	for _, v := range dataSlice {
		title := v.(map[string]interface{})["title"].(string)
		idiom := Idiom{Title: title}
		idiomsMap[title] = idiom
	}
	return
}

//将精确查询的json转化为go数据
func ParseJson2Idiom(jsonStr string) Idiom {
	idiom := Idiom{}
	tempMap := make(map[string]interface{})
	json.Unmarshal([]byte(jsonStr), &tempMap)
	dataMap := tempMap["showapi_res_body"].(map[string]interface{})["data"].(map[string]interface{})
	for k, v := range dataMap {
		valueStr := v.(string)
		switch k {
		case "title":
			idiom.Title = valueStr
		case "spell":
			idiom.Spell = valueStr
		case "samples":
			idiom.Sample = valueStr
		case "derivation":
			idiom.Derivation = valueStr
		case "content":
			idiom.Content = valueStr
		}
	}
	return idiom
}

//将go数据写出到json文件
func WriteIdioms2File(idiomsMap map[string]Idiom, path string) {
	fmt.Println("WriteIdioms2File")
	dstFile, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	defer dstFile.Close()

	encoder := json.NewEncoder(dstFile)
	err := encoder.Encode(idiomsMap)
	if err != nil {
		fmt.Println("写出json文件失败,err=", err)
		return
	}
	fmt.Println("写出json文件成功!")
}

//读入json文件为go数据
func ReadIdiomsFromFile(dstPath string) (idiomsMap map[string]Idiom, err error) {
	idiomsMap = make(map[string]Idiom)

	//读入json文件数据
	dstFile, _ := os.OpenFile(dstPath, os.O_RDONLY|os.O_CREATE, 0666)
	defer dstFile.Close()
	decoder := json.NewDecoder(dstFile)
	err = decoder.Decode(&idiomsMap)
	if err != nil {
		fmt.Println("加载数据失败!err=", err)
	} else {
		fmt.Println("成功加载数据!")
		fmt.Println("idiomsMap=", idiomsMap)
	}
	return
}

定义网络工具

import (
	"net/http"
	"fmt"
	"io/ioutil"
)

//获取模糊查询的url
func GetAmbiguousUrl(keyword string,page string)(url string){
	return "http://route.showapi.com/1196-1?showapi_appid=19988&showapi_sign=968ad4fcc2144e41b5c366838d1b0ec4&keyword="+keyword+"&page="+page+"&rows=20"
}

//获取精确查询的url
func GetAccurateUrl(keyword string)(url string){
	return "http://route.showapi.com/1196-2?showapi_appid=19988&showapi_sign=968ad4fcc2144e41b5c366838d1b0ec4&keyword="+keyword
}

//从url拿到json数据
func GetJson(url string) (jsonStr string, err error) {

	//获得网络数据
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("http请求失败,err=", err)
		return
	}
	//延时关闭网络IO资源
	defer resp.Body.Close()

	//resp.Body实现了Reader接口,对其进行数据读入
	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("读取网络数据失败,err=", err)
		return
	}

	//将网络数据转化为字符串输出
	jsonStr = string(bytes)
	//fmt.Println(jsonStr)

	return
}

//模糊查询
func DoAmbiguousQuery(keyword string,page string,chanAccurate chan<- string) {
	//先拿到json
	url := GetAmbiguousUrl(keyword, page)
	jsonStr, _ := GetJson(url)

	//将json转化为成语集合
	idiomsMap := ParseJson2Idioms(jsonStr)

	//将成语集合写入内存数据
	for title,idiom := range idiomsMap{
		dbDataMap[title] = idiom
	}

	//将成语的名字写入精确管道
	for title,_ := range idiomsMap{
		chanAccurate<- title
	}

/*	chanAccurate<- "大鹏展翅"
	chanAccurate<- "隔壁老王"
	chanAccurate<- "龟派气功"
	chanAccurate<- "我很牛逼"
	chanAccurate<- "来咬我呀"
	fmt.Println("DoAmbiguousQuery",keyword,page)
*/
}

//精确查询
func DoAccurateQuery(keyword string) {
	//fmt.Println("DoAccurateQuery",keyword)

	//拿到json
	url := GetAccurateUrl(keyword)
	jsonStr, _ := GetJson(url)

	//将json转化为一个Idiom对象
	idiom := ParseJson2Idiom(jsonStr)

	//将Idiom对象存入总集合,覆盖原来的粗糙对象
	dbDataMap[idiom.Title] = idiom

}

主调模块

import (
	"fmt"
	"time"
	"os"
)

const DB_PATH = "d:/temp/idioms-v2.0.json"

var (
	//数据管道
	chanAmbiguous = make(chan string, 20)
	chanAccurate  = make(chan string, 20)
	chanQuit      = make(chan string, 0)

	//全局内存数据
	dbDataMap = make(map[string]Idiom)
)

func main0() {

	//读入命令行参数
	//idiom.exe -cmd start -poem 大王派我来巡山
	cmdInfo := [3]interface{}{"cmd","未知命令","你打算干什么"}
	poemInfo := [3]interface{}{"poem","绞尽果汁想不出","用于启动的一行诗句"}
	retValuesMap := GetCmdlineArgs(cmdInfo,poemInfo)
	cmd := retValuesMap["cmd"].(string)
	poem := retValuesMap["poem"].(string)
	fmt.Println(cmd, poem)

	//将读入的诗句打碎丢入模糊管道
	for _, v := range poem {
		keyword := fmt.Sprintf("%c", v)
		chanAmbiguous <- keyword
	}

	//三选一读入管道数据,周期性执行
	go func() {
		ticker := time.NewTicker(time.Second)
		for {
			<-ticker.C
			select {
			case keyword := <-chanAmbiguous:
				go DoAmbiguousQuery(keyword,"1",chanAccurate)
			case keyword := <-chanAccurate:
				go DoAccurateQuery(keyword)

			case <-chanQuit:
				WriteIdioms2File(dbDataMap, DB_PATH)
				os.Exit(0)
			}
		}
	}()

	//定时20秒结束主程序
	timer := time.NewTimer(20 * time.Second)
	<-timer.C
	chanQuit <- "OVER"

}

学院Go语言视频主页

https://edu.csdn.net/lecturer/1928

清华团队带你实战区块链开发

扫码获取海量视频及源码 QQ群:721929980

Go语言项目实战:基于开源数据的成语查询

以上所述就是小编给大家介绍的《Go语言项目实战:基于开源数据的成语查询》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Cult of the Amateur

The Cult of the Amateur

Andrew Keen / Crown Business / 2007-6-5 / USD 22.95

Amateur hour has arrived, and the audience is running the show In a hard-hitting and provocative polemic, Silicon Valley insider and pundit Andrew Keen exposes the grave consequences of today’s......一起来看看 《The Cult of the Amateur》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

URL 编码/解码
URL 编码/解码

URL 编码/解码