参考资料:1.Python中用json.load() json.loads()加载json数据的方法:
2. python中yield的用法详解:
一个很有趣的项目,输入主题,分分钟洋洋洒洒上万字形式主义大作。
网页版在线生成器:https://suulnnka.github.io/BullshitGenerator/index.html
效果:
作者声明:
偶尔需要一些中文文字用于GUI开发时测试文本渲染. 本项目只做这一项, 请勿用于其他任何用途.
再次声明一下, 本项目生成的文章真的狗屁不通, 只能拿来搞笑, 请不要用于正规用途!关于中文变量名:
平时撸码鄙人是不写中文变量名的, 本项目中的中文变量名只是最开始瞎写的时候边写语料边写代码时懒得切英文输入法了. 不过既然如此就保持吧!
关于生成算法:
鄙人才疏学浅并不会任何自然语言处理相关算法. 而且目前比较偏爱简单有效的方式达到目的方式. 除非撞到了天花板, 否则暂时不会引入任何神经网络等算法. 不过欢迎任何人另开分支实现更复杂, 效果更好的算法. 不过除非效果拔群, 否则鄙人暂时不会融合.
一、项目概览
项目中提供了在线版和Python3版本两种,其中与Python版本有关的文件有3个,自动狗屁不通文章生成器.py(主框架),readJSON.py(读取JSON库),data.json(储存名言和废话)
二、代码分析
readJSON.py
def 读JSON文件(fileName=""):
import json
if fileName!='':
strList = fileName.split(".")
if strList[len(strList)-1].lower() == "json":
with open(fileName,mode='r',encoding="utf-8") as file:
return json.loads(file.read())
- 这个函数的核心是后两句:获取文件句柄,利用
read()
函数,将file中的数据转化为str字符串,再利用json.loads()
函数将字符串转换成dict字典类型返回。 - 前面的代码是为了增强代码的稳定性,防止因为文件名导致的文件读写错误。
- 关于
json.loads()
函数,请参考Python中用json.load() json.loads()加载json数据的方法
自动狗屁不通文章生成器.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import random
import readJSON
data = readJSON.读JSON文件("data.json")
名人名言 = data["famous"] # a 代表前面垫话,b代表后面垫话
前面垫话 = data["before"] # 在名人名言前面弄点废话
后面垫话 = data['after'] # 在名人名言后面弄点废话
废话 = data['bosh'] # 代表文章主要废话来源
xx = "学生会退会"
重复度 = 2
def 洗牌遍历(列表):
global 重复度
池 = list(列表) * 重复度
while True:
random.shuffle(池)
for 元素 in 池:
yield 元素
下一句废话 = 洗牌遍历(废话)
下一句名人名言 = 洗牌遍历(名人名言)
def 来点名人名言():
global 下一句名人名言
xx = next(下一句名人名言)
xx = xx.replace("a", random.choice(前面垫话))
xx = xx.replace("b", random.choice(后面垫话))
return xx
def 另起一段():
xx = ". "
xx += "\r\n"
xx += " "
return xx
if __name__ == "__main__":
xx = input("请输入文章主题:")
for x in xx:
tmp = str()
while len(tmp) < 6000:
分支 = random.randint(0, 100)
if 分支 < 5:
tmp += 另起一段()
elif 分支 < 20:
tmp += 来点名人名言()
else:
tmp += next(下一句废话)
tmp = tmp.replace("x", xx)
print(tmp)
1.洗牌遍历
def 洗牌遍历(列表):
global 重复度
池 = list(列表) * 重复度
while True:
random.shuffle(池)
for 元素 in 池:
yield 元素
下一句废话 = 洗牌遍历(废话)
下一句名人名言 = 洗牌遍历(名人名言)
池 = list(列表) * 重复度
将列表重复了n次random.shuffle()
函数将“池”中元素打乱重新排列- yield:
这个应该是整个项目里面最难懂的部分,本人之前也没接触过这种用法(可能是因为我太菜了),在网上搜索了相关用法,这个是我觉得讲的最好的一篇博客:python中yield的用法详解带yield的函数是一个生成器(Generator),下面的“下一句废话”与“下一句名人名言”相当于他的两个实例。每一次使用next()
函数时,从上一次的yield中断处开始运行,直至遇到下一个yield中断运行并返回相应值,如果遇到return或者函数体结尾,自动抛出StopIteration异常。
对于这段代码,通过一个for循环,保证每一次返回的元素都与上一次不同。
2.来点名人名言
def 来点名人名言():
global 下一句名人名言
xx = next(下一句名人名言)
xx = xx.replace("a", random.choice(前面垫话))
xx = xx.replace("b", random.choice(后面垫话))
return xx
不得不说作者的函数名起得还是很魔性的,O(∩_∩)O哈哈~
- 在这里我们见到了在上一个函数内介绍的
next()
函数,xx = next(下一句名人名言)
,即从上一次调用洗牌遍历(名人名言)
这一函数的yield中断处开始执行,通过for循环,返回了一个名人名言。 - 名人名言的格式:名人+a+名言+b,如“爱迪生a,天才是百分之一的勤奋加百分之九十九的汗水。b”,所以作者要对a和b进行替换,
random.choice()
函数返回列表中的一个随机值,作者从前面垫话和后面垫话的列表中各取出一句,然后利用replace()
这一字符串处理函数替换掉原来的a和b,这时xx已经成为一个完整的名人名言了。
3.另起一段
def 另起一段():
xx = ". "
xx += "\r\n"
xx += " "
return xx
这个函数没什么好说的,就是一个句号+换行符+首行缩进。
4.main函数
if __name__ == "__main__":
xx = input("请输入文章主题:")
for x in xx:
tmp = str()
while len(tmp) < 6000:
分支 = random.randint(0, 100)
if 分支 < 5:
tmp += 另起一段()
elif 分支 < 20:
tmp += 来点名人名言()
else:
tmp += next(下一句废话)
tmp = tmp.replace("x", xx)
print(tmp)
- for循环遍历文章主题的字符串,如果在输入文章主题时直接回车,那么程序会直接结束。
- for循环的次数和字符串长度有关,for循环内部生成一个6000字左右的字符串,所以生成的文章的总长度与文章主题的长度成正相关关系,文章主题每多一个字,文章长度就会增加6000字左右,小伙伴们可以自行验证一下。
- 分支:
random.randint(0,100)
生成一个0~100之间的随机整数(包括0和100),如果在0~4之间,另起一段,5~19添加名人名言,20~100添加废话,所以说按照概率从大到小排序:添加废话>添加名人名言>另起一段 - 废话中有x表示需要填充的文章主题,
tmp = tmp.replace("x",xx)
将文章中所有的x都替换成文章主题,注意:**这句函数中的“x”是加引号的,要与for x in xx:
中的x区分开。**之后,把生成的文章print出来,就完成了!
综上,我们看完了BullshitGenerator的整个代码,不知道你们感觉怎样,反正我这个Python小白是收获满满。文章中难免有错误纰漏之处,欢迎大家批评指正。