使用Go默写古诗词

2024-02-08 11:40
文章标签 go 使用 古诗词 默写

本文主要是介绍使用Go默写古诗词,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

“白日依山尽,___”。下句自然填黄河入海流,那么“日月忽其不淹兮,___,___,恐美人之迟暮”,中间两句怎么填呢?

最近工作中有个需求,就是1500道语文诗词填空题没有答案,现在需要给这些题目大爷们匹配它们对应的答案,好在题目信息都很完整,指出了诗词出处、作者信息。自然想到到网上爬取对应文章信息然后字符串匹配答案。目前做完,效果还可以,基本上所有题目的答案都有了,现把操作流程记录下,做个总结。

1. 文章信息获取

网上找了很久,目前发现百度汉语对古诗词收录的比较好,格式也比较规范,整个爬取过程还是比较简单,浏览器分析网站,找到它们的搜索接口:http://hanyu.baidu.com/hanyu/ajax/sugs只需要传一个参数:mainkey,是一个urlencode格式的字符串。接口会返回一个匹配列表,再用作者名称对这个列表做筛选,详细代码如下:

    baseUrl := "http://hanyu.baidu.com/hanyu/ajax/sugs?"client := &http.Client{}u, _ := url.Parse(baseUrl)q := u.Query()q.Set("mainkey", name)u.RawQuery = q.Encode()//添加Headerreq, _ := http.NewRequest("GET", u.String(), nil)req.Header.Add("User-Agent", `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36`)req.Header.Add("DNT", "1")req.Header.Add("Host", "hanyu.baidu.com")req.Header.Add("Accept-Language", "zh-CN,zh;q=0.8")req.Header.Add("Referer", "http://hanyu.baidu.com/shici/detail?pid=be520db056da43238035dc18bb1e1798&tn=sug_click")resp, errDo := client.Do(req)

拿到返回值以后,筛选出对应的作者信息。

//如果有多个搜索结果,比对author是否正确respJson.ForEach(func(key, value gjson.Result) bool {//先看看有没有display_namedisplayName := value.Get("display_name.0").String()sid := value.Get("sid.0").String()if len(displayName) == 0 {//不是这条记录return true}//看看typetypeStr := value.Get("type.0").String()if typeStr == "poemline"{//取SourcedisplayName = value.Get("source_poem.0").String()sid = value.Get("source_poem_sid.0").String()}literatureAuthor := value.Get("literature_author.0").String()//author是否一致if literatureAuthor == author {searchResult.Sid = sidsearchResult.DisplayName = displayNamesearchResult.Author = literatureAuthorreturn false}return true // keep iterating})

SearchResult保存了搜索到的结果,根据sid拿到文章页面,解析出其中的文章。

func GetContent(sid string) (content string, err error) {baseUrl := "http://hanyu.baidu.com/shici/detail"result := make([]string, 0, 0)client := &http.Client{}u, _ := url.Parse(baseUrl)q := u.Query()q.Set("pid", sid)u.RawQuery = q.Encode()req, _ := http.NewRequest("GET", u.String(), nil)req.Header.Add("User-Agent", `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36`)req.Header.Add("DNT", "1")req.Header.Add("Host", "hanyu.baidu.com")req.Header.Add("Accept-Language", "zh-CN,zh;q=0.8")req.Header.Add("Referer", "http://hanyu.baidu.com/shici/detail?pid=be520db056da43238035dc18bb1e1798&tn=sug_click")resp, errDo := client.Do(req)if errDo != nil || resp.StatusCode != 200 {err = errors.New("无法连接百度汉语 " + errDo.Error())return}docm, errDoc := goquery.NewDocumentFromResponse(resp)if errDoc != nil {err = errors.New("解析Doc错误 " + errDoc.Error())return}//诗词信息都保存在 body_p 的div中,可以通过PuerkitoBio/goquery库获取pSelect := docm.Find("#body_p")pSelect.Each(func(pos int, selection *goquery.Selection) {content := strings.TrimSpace(selection.Text())result = append(result, content)})content = strings.Join(result, "")return
}

目前会爬取百度汉语、古诗词两个网站的数据,如果有更好的数据源,只需要实现Spider接口,在MapSpiderManifest()方法中注册即可。

type Spider interface {GetContent(SearchResult) (string, error)FindContent(string, string) (SearchResult, error)
}func MapSpiderManifest() map[string]Spider {//初始化并且注册所有的SpiderspiderMap := make(map[string]Spider)//百度baiduSpider := new(BaiduSpider)spiderMap["baiduSpider"] = baiduSpider//古诗文网gushiwenSpider := new(GushiwenSpider)spiderMap["gushiwenSpider"] = gushiwenSpiderreturn spiderMap
}

2.诗词句子查找

古诗文默写,以前上学的时候做的多了,把一句话抠出来,随机选其中几段话让学生默写。一般可以归类为一下几种模式:

  1. 开头留空 :_,[_,…],何人不起故园情。
  2. 末尾留空:俱往矣,_,[_,…]。
  3. 中间留空:月出于东山之上,_,白露横江,

不管是什么样的模式,就每个填空处来看,只有它前面或者后面有提示句,我们才能知道这个空的答案是什么。也就是说,这样的填空可以自主的找到答案,姑且称之为自主空。而前后都没有提示句的空,只能等待附近有自主空找到了答案,才能找到它本身的答案,用一个图说明更加清晰:

image

图中灰色的块因为有提示句,所以可以通过步骤一种爬取下来的文章内容找到对应的答案,填入Blank中,具体的查找算法如下代码所示:

//已知newFind的PreString,求BlankString和PostString
func makeWithPreContent(contentsSplit []string, newFind *Find) {for l := range contentsSplit {if isEqual(contentsSplit[l], newFind.PreString) && l < len(contentsSplit)-1 {newFind.BlankString = contentsSplit[l+1]if l < len(contentsSplit)-2 {newFind.PostString = contentsSplit[l+2]}newFind.BlankFinish = true}}
}//已知newFind的PostString,求BlankString和PreString
func makeWithPostContent(contentsSplit []string, newFind *Find) {for l := range contentsSplit {if isEqual(contentsSplit[l], newFind.PostString) && l > 0 {newFind.BlankString = contentsSplit[l-1]if l-1 > 0 {newFind.PreString = contentsSplit[l-2]}newFind.BlankFinish = true}}
}// 按标点符号分隔内容
func SplitByPunctuation(s string) ([]string, []string) {regPunctuation, _ := regexp.Compile(`[,,。.??!!;;::]`)//匹配标点符号,保存下来。 然后分割字符串toPun := regPunctuation.FindAllString(s, -1)result := regPunctuation.Split(s, -1)if len(result[len(result)-1]) == 0 {result = result[:len(result)-1]}//去掉前后空格,去掉引号for i := range result {result[i] = strings.TrimSpace(result[i])regQuoting := regexp.MustCompile("[“”‘’']")result[i] = regQuoting.ReplaceAllString(result[i], "")}return result, toPun
}

所有的自主块都找到答案后,可以把每个自主块看作一个双向链表的表头,我们所要做的就是遍历每个双向链表,把其中每个节点的答案都通过查找算法找出来。当下一个节点是NULL,或者下个节点是一个自主块时,就停止遍历,处理下一个双向链表。这样,无论给出的需要填空的内容多么复杂,都可以顺利的完整自动填写工作。

3.效果

一些常用的文言文或诗词:

1、 前赤壁赋

github

2、 离骚

github


项目地址:
AncientPoetryFillBlank

这篇关于使用Go默写古诗词的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/690911

相关文章

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Java 日志中 Marker 的使用示例详解

《Java日志中Marker的使用示例详解》Marker是SLF4J(以及Logback、Log4j2)提供的一个接口,它本质上是一个命名对象,你可以把它想象成一个可以附加到日志语句上的标签或戳... 目录什么是Marker?为什么使用Markejavascriptr?1. 精细化的过滤2. 触发特定操作3

Linux五种IO模型的使用解读

《Linux五种IO模型的使用解读》文章系统解析了Linux的五种IO模型(阻塞、非阻塞、IO复用、信号驱动、异步),重点区分同步与异步IO的本质差异,强调同步由用户发起,异步由内核触发,通过对比各模... 目录1.IO模型简介2.五种IO模型2.1 IO模型分析方法2.2 阻塞IO2.3 非阻塞IO2.4

使用Go调用第三方API的方法详解

《使用Go调用第三方API的方法详解》在现代应用开发中,调用第三方API是非常常见的场景,比如获取天气预报、翻译文本、发送短信等,Go作为一门高效并发的编程语言,拥有强大的标准库和丰富的第三方库,可以... 目录引言一、准备工作二、案例1:调用天气查询 API1. 注册并获取 API Key2. 代码实现3

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

MySQL8.0临时表空间的使用及解读

《MySQL8.0临时表空间的使用及解读》MySQL8.0+引入会话级(temp_N.ibt)和全局(ibtmp1)InnoDB临时表空间,用于存储临时数据及事务日志,自动创建与回收,重启释放,管理高... 目录一、核心概念:为什么需要“临时表空间”?二、InnoDB 临时表空间的两种类型1. 会话级临时表

MySQL之复合查询使用及说明

《MySQL之复合查询使用及说明》文章讲解了SQL复合查询中emp、dept、salgrade三张表的使用,涵盖多表连接、自连接、子查询(单行/多行/多列)及合并查询(UNION/UNIONALL)等... 目录复合查询基本查询回顾多表查询笛卡尔积自连接子查询单行子查询多行子查询多列子查询在from子句中使

Kotlin 协程之Channel的概念和基本使用详解

《Kotlin协程之Channel的概念和基本使用详解》文章介绍协程在复杂场景中使用Channel进行数据传递与控制,涵盖创建参数、缓冲策略、操作方式及异常处理,适用于持续数据流、多协程协作等,需注... 目录前言launch / async 适合的场景Channel 的概念和基本使用概念Channel 的

C#使用SendMessage实现进程间通信的示例代码

《C#使用SendMessage实现进程间通信的示例代码》在软件开发中,进程间通信(IPC)是关键技术之一,C#通过调用WindowsAPI的SendMessage函数实现这一功能,本文将通过实例介绍... 目录第一章:SendMessage的底层原理揭秘第二章:构建跨进程通信桥梁2.1 定义通信协议2.2

使用python制作一款文件粉碎工具

《使用python制作一款文件粉碎工具》这篇文章主要为大家详细介绍了如何使用python制作一款文件粉碎工具,能够有效粉碎密码文件和机密Excel表格等,感兴趣的小伙伴可以了解一下... 文件粉碎工具:适用于粉碎密码文件和机密的escel表格等等,主要作用就是防止 别人用数据恢复大师把你刚删除的机密的文件恢