python对对联

网络 分享 时间: 收藏本文

python对对联

1.项目目的

编写一段能够根据输入的上联对出下联的对对联程序。输入上联后,能随机生成下联,最终达到:

(1) 程序的智能性高,功能完善。希望生成的对联满足平仄、韵脚、词性等要求,并具有一定语义。

(2) 在实践项目的过程中提高同学的代码编写能力。具体能力包括:程序设计知识的综合运用能力;自主学习、错误调试的能力;规范书写代码及报告的意识和能力;阅读代码、改写代码的能力等。

2.项目内容

这是一个运用从网上爬取的对联、通过随机的算法生成一段符合押韵、平仄规则的对联的程序。大体过程为:

(1) 运用、、Re模块等从网站上爬取对联,并对对联进行文本格式处理;

(2) 运用模块对对联进行词性分析,运用模块对对联进行平仄校准;

(3) 根据词频随机做出符合押韵、平仄规则的下联。

3.输入输出

输入:任意一副对联的某一联

输出:判断该联为上联或下联并随机生成满足平仄、韵脚的另一联

程序流程图

爬虫分析&数据分析 1.爬虫整体思路

(1)爬取网页

选择想要爬取的网址,并模拟头部浏览器访问该网站。创建一个dict,将头部信息以键值对的形式存入到dict对象中。本次项目爬取的网址为:

然后调用..()函数创建一个对象,该函数第一个参数传入url,第二个参数可以传入数据,默认是传入0数据,第三个参数是传入头部,该参数也是有默认值的,默认是不传任何头部。将dict对象传入..()函数第三个参数。

此时,已经成功设置好报头,然后使用()打开该对象即可打开对应的网址。然后使用.read() 接收 json 数据, 数据格式为UTF-8

(2) 逐一获取需要的标签并解析数据

可以看到在网页中我们需要的对联内容在p标签内,因此从html中获取p标签内容, 再利用正则表达式匹配符合要求的内容, 并将其写入数据库

(3)保存内容

主要涉及文件的读写。

代码如下:

# 取消服务器证书验证功能
ssl._create_default_https_context = ssl._create_unverified_context
database = []  # 列表记录数据
def askUrl(i):  # 得到指定一个URL的网页内容
    global database
    # 爬取对联大全网站
    url = "http://duilian.haoshiwen.org/view.php?aid=" + str(i)
    head = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54"
    }  # 模拟头部浏览器
    try:  # 用try except进行异常处理
        request = urllib.request.Request(url, headers=head)
        response = urllib.request.urlopen(request)
        html = response.read().decode("UTF-8")
        selector = etree.HTML(html)  # 将源码转化为能被XPath匹配的格式
        result = selector.xpath('//p/text()')  # 返回所有p标签
        for html in result:
            findCouplet = re.compile(r'[\u4e00-\u9fff]{7}')  # 使用正则表达式查找符合格式的内容
            couplet = re.findall(findCouplet, html)
            if couplet:
                database.append(couplet)  # 写入数据库
    except urllib.error.URLError as e:
        if hasattr(e, "code"):
            print(e.code)
        if hasattr(e, "reason"):
            print(e.reason)

因为该网站的数据格式多样, 我自己爬到的数据比较少,所以我下载了网上的数据库来作为扩充(包含约70万条对联),下载地址如下:

中国对联数据集 -

.txt(上联)和.txt(下联)两个文件

2. 算法分析 模块是通过学习,记录词频

这部分是逐个分析上联中的词语,如获得一个词语后,在下联中找到这个词语可以匹配的词,并根据该词语匹配的次数用公式计算词频概率(对应概率越大说明该词最有可能与上联中的对应词匹配)。计算公式是多次试验后发现的比较能反映词频的算法,不一定是最优。

代码如下:

# 对联学习
def learns():
   global infile, outfile, zishi
   size = len(infile)  # infile为上联库中的内容
   for i in range(size):
       cut = jieba.lcut(infile[i])  # 对上联库中对联逐一分词
       for j in range(len(cut)):
           position = infile[i].find(cut[j])  # 找到该词位置
           learn(cut[j], outfile[i][position: position + len(cut[j])])  # 学习该词
       for j in range(len(infile[i])):
           learn(infile[i][j], outfile[i][j])  # 学习对联中每个字
# 单个的词语学习
def learn(word, nword):
   global zishi
   zikey = zishi.keys()
   if word in zikey:  # 如果该词语已被学习过
       zishikey = zishi[word].keys()  # 获取所有可以匹配该词的词语
       if nword in zishikey:  # 如果下联对应词在可匹配词语中
           for j in zishikey:
               if j != '$':
                   if j != nword:  # 可匹配词语中的其他词对应概率减小
                       zishi[word][j] = zishi[word][j] / (1 + 1 / zishi[word]['$'])
           zishi[word][nword] = (zishi[word][nword] + 1 / zishi[word]['$']) / (1 + 1 / zishi[word]['$'])
           # 该对应词的概率增大
           zishi[word]['$'] = zishi[word]['$'] + 1  # 可匹配词语总数+1
       else:  # 如果该词语未被学习过(以下步骤同上)
           for j in zishikey:
               if j != '$':
                   zishi[word][j] = zishi[word][j] / (1 + 1 / zishi[word]['$'])
           zishi[word][nword] = (1 / zishi[word]['$']) / (1 + 1 / zishi[word]['$'])
           zishi[word]['$'] = zishi[word]['$'] + 1
   else:
       zishi[word] = {'$': 1, nword: 1}

这是学习后生成的文件:

意思为:“上联”:{“$”+匹配的总字数,“下联1”:对应概率,“下联2”:对应概率……}

平仄方法区分

看对联的最后一个字,上联最后一个字是三声和四声(仄声),下联的最后一个字是一声和二声(平声),如下联:兴xīng 一声 是上联,旺wàng四声是下联。

def is_down(content):  # 判断是否是下联, 如果是返回true
   s = list(content)
   a = pinyin.get(s[-1], format="numerical")[-1]
   return a == '1' or a == '2'

main模块讲解:

首先如果用户输入1, 进行对联自动生成的话,打开学习生成的文件, 用和ran函数实现匹配并生成下联:在函数中,用随机为上联分配一个权重/概率(达到随机匹配目的),对上联分词后的词语一一使用ran函数,然后再组合成上联。在ran函数中,将上联分配到的概率r与所有能配对的词语一一比较,如果比较到某个词的概率大于r,就返回该词i。否则使r减少后再重复以上步骤。然后进行输出,输出时进行平仄校验,平仄正确率大于80%后直接输出,否则再次随机生成下联,直到平仄符合。

以下介绍模块,主要是自定义的jy函数:

方法比较简单,就是获取每个字的音调后一一比对, 如果平仄不对则记录下来, 最后拿正确数除以总的字数获得正确率。

代码如下:

import pinyin
def is_down(content):  # 判断是否是下联, 如果是返回true
    s = list(content)
    a = pinyin.get(s[-1], format="numerical")[-1]
    return a == '1' or a == '2'
def jy(s, x):
    s = list(s)
    x = list(x)
    yin1 = []
    yin2 = []
    for i in s:  # 获取对联中每个字的拼音声调
        a = pinyin.get(i, format="numerical")
        yin1.append(a[-1])
    for i in x:
        b = pinyin.get(i, format="numerical")
        yin2.append(b[-1])
    error = 0
    length = len(yin1)
    for i in range(length):  # 比对平仄
        if (yin1[i] == '1' or yin1[i] == '2') and (yin2[i] == '1' or yin2[i] == '2'):
            error += 1
        if (yin1[i] == '3' or yin1[i] == '4') and (yin2[i] == '3' or yin2[i] == '4'):
            error += 1
    # 平仄正确率输出
    return (length - error * 1.0) / length

如果用户输入2, 则调用jy函数输出平仄的评分。

代码如下:

import jieba
import random
import json
from verify import jy, is_down
def couplet(s):  # 生成另一联
    R = 0
    x = []
    for i in range(len(s)):
        x.append(ran(s[i], random.random()))
        # 用random随机生成一个0到1之间的数后,用ran函数进行权重比较、随机输出
    return "".join(x)
def ran(w, r):
    # 根据随机赋予字词的权重进行比较
    global zishi, writemode, R
    R = 0
    zikey = zishi.keys()  ##返回字典中所有键
    if w != '' and w in zikey:  # 当所输上联在对联库中,根据库得出下联
        zishikey = zishi[w].keys()
        max = ["", 0.0]
        for i in zishikey:
            if i != '$':
                if r < float(zishi[w][i]):  # 当该权重小于匹配到的字词对应概率,返回该字词
                    R += r
                    return i
                else:  # 减小权重,再次比较
                    r = r - float(zishi[w][i])
        return max[0]
    else:  # 如果该上联不在数据库中,划分字词后逐词匹配
        return "".join([ran(i, random.random()) for i in w])
if __name__ == '__main__':
    # 引入校验函数
    global infile, outfile, zishi, writemode, R
    try:
        with open("zknow.txt", "r", encoding='utf-8') as zishi_file:
            # 打开学习后生成的文件
            zishi = json.loads(zishi_file.read().replace("'", '"'))
            # 将json格式数据解码为python对象,构建字典
    except IOError:
        zishi = {}
    while True:
        choice = input("1. 自动对对联 2. 对联评分")
        if choice == "1":
            s = input("输入对联:")
            s = jieba.lcut(s)  # 对联切词
            x = couplet(s)  # 生成另一联
            s = "".join(s)
            for i in range(1000):
                # 检验平仄,平仄正确率大于百分之80后直接输出,否则再次随机生成下联,直到平仄符合
                pz = jy(s, x)
                if pz >= 0.8:
                    print("-----------------------------------")
                    if is_down(s):
                        print("上联:" + x)
                        print("下联:" + s)
                    else:
                        print("上联:" + s)
                        print("下联:" + x)
                    print("-----------------------------------")
                    print("评分:")
                    print("平仄: " + str(round(pz * 100, 2)) + "分")
                    print("对仗: " + str(round(R * 10000, 2)) + "分")
                    break
                else:
                    x = couplet(s)
        else:
            s = input("输入上联:")
            x = input("输入下联:")
            pz = jy(s, x)
            print("评分:")
            print("平仄: " + str(round(pz * 100, 2)) + "分")

实验结果&对比分析

1.实验结果

运行结果:

信息流广告 网络推广 周易 易经 代理招生 二手车 网络营销 招生代理 旅游攻略 非物质文化遗产 查字典 精雕图 戏曲下载 抖音代运营 易学网 互联网资讯 成语 成语故事 诗词 工商注册 注册公司 抖音带货 云南旅游网 网络游戏 代理记账 短视频运营 在线题库 国学网 知识产权 抖音运营 雕龙客 雕塑 奇石 散文 自学教程 常用文书 河北生活网 好书推荐 游戏攻略 心理测试 石家庄人才网 考研真题 汉语知识 心理咨询 手游安卓版下载 兴趣爱好 网络知识 十大品牌排行榜 商标交易 单机游戏下载 短视频代运营 宝宝起名 范文网 电商设计 免费发布信息 服装服饰 律师咨询 搜救犬 Chat GPT中文版 经典范文 优质范文 工作总结 二手车估价 实用范文 爱采购代运营 古诗词 衡水人才网 石家庄点痣 养花 名酒回收 石家庄代理记账 女士发型 搜搜作文 石家庄人才网 铜雕 词典 围棋 chatGPT 读后感 玄机派 企业服务 法律咨询 chatGPT国内版 chatGPT官网 励志名言 河北代理记账公司 文玩 朋友圈文案 语料库 游戏推荐 男士发型 高考作文 PS修图 儿童文学 买车咨询 工作计划 礼品厂 舟舟培训 IT教程 手机游戏推荐排行榜 暖通,电地暖, 女性健康 苗木供应 ps素材库 短视频培训 优秀个人博客 包装网 创业赚钱 养生 民间借贷律师 绿色软件 安卓手机游戏 手机软件下载 手机游戏下载 单机游戏大全 免费软件下载 网赚 手游下载 游戏盒子 职业培训 资格考试 成语大全 英语培训 艺术培训 少儿培训 苗木网 雕塑网 好玩的手机游戏推荐 汉语词典 中国机械网 美文欣赏 红楼梦 道德经 标准件 网站转让 鲜花 社区团购 石家庄论坛 书包网 电地暖