python写对联_Python编程软件有哪些[通俗易懂]

python写对联_Python编程软件有哪些[通俗易懂]python对对联_用puthon写春联

1.项目目的

编写一段能够根据输入的上联对出下联的Python对对联程序。输入上联后,能随机生成下联,最终达到:
(1) 程序的智能性高,功能完善。希望生成的对联满足平仄、韵脚、词性等要求,并具有一定语义。
(2) 在实践项目的过程中提高同学的代码编写能力。具体能力包括:程序设计知识的综合运用能力;自主学习、错误调试的能力;规范书写代码及报告的意识和能力;阅读代码、改写代码的能力等。

2.项目内容

这是一个运用从网上爬取的对联、通过随机的算法生成一段符合押韵、平仄规则的对联的程序。大体过程为:
(1) 运用xPath、Request、Re模块等从网站上爬取对联,并对对联进行文本格式处理;
(2) 运用jieba模块对对联进行词性分析,运用pinyin模块对对联进行平仄校准;
(3) 根据词频随机做出符合押韵、平仄规则的下联。

3.输入输出

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

程序流程图

在这里插入图片描述

爬虫分析&数据分析

1.爬虫整体思路

(1)爬取网页
选择想要爬取的网址,并模拟头部浏览器访问该网站。创建一个dict,将头部信息以键值对的形式存入到dict对象中。本次项目爬取的网址为: http://duilian.haoshiwen.org
然后调用urllib.request.Request()函数创建一个request对象,该函数第一个参数传入url,第二个参数可以传入数据,默认是传入0数据,第三个参数是传入头部,该参数也是有默认值的,默认是不传任何头部。将dict对象传入urllib.request.Request()函数第三个参数。
此时,已经成功设置好报头,然后使用urlopen()打开该Request对象即可打开对应的网址。然后使用response.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万条对联),下载地址如下:
中国对联数据集 – Heywhale.com
train_in.txt(上联)和train_out.txt(下联)两个文件

2. 算法分析

  1. Lear_data模块是通过学习,记录词频

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

代码如下:

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

以下介绍verify模块,主要是自定义的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.实验结果
运行结果:
在这里插入图片描述

今天的文章python写对联_Python编程软件有哪些[通俗易懂]分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/63534.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注