这几天在论坛上看到了一个很有意思的项目,一个生成“狗屁不通”的文章的程序。经过本人确定其的确是“狗屁不通”后,随后又好奇其实现,于是在其[GitHub]项目里(https://github.com/menzi11/BullshitGenerator)找到源码,研究了半晌。

我看的是网页版的,就是JS文件里的核心代码。

作者使用了大量的中文变量名,请谨慎阅读,若有不适请立即离开

声明的String数组--组成文章的核心内容

let 主题 = "一天掉多少根头发";    //用户输入的文字(会围绕该文字“生成”文章)

let 论述 = [
"现在,解决主题的问题,是非常非常重要的。 所以, ",
"我们不得不面对一个非常尴尬的事",
//略,这里有很多的这种论述 ]; let 名人名言 = [
"伏尔泰曾经说过,不经巨大的困难,不会有伟大的事业。这不禁令我深思",
"富勒曾经说过,苦难磨炼一些人,也毁灭另一些人。这不禁令我深思",
//略,这里有很多名人名言]; let 后面垫话 = [
"这不禁令我深思。 ",
"带着这句话,我们还要更加慎重的审视这个问题: ",
"这启发了我, ",]; let 前面垫话 = [
"曾经说过",
"在不经意间这样说过",
];

上面的字符串数组是此程序的“基石”,也是可以通过修改其内容从而改变文章“内容”的重要备份

声明的几个函数--“合成”文章的核心算法

function 随便取一句(列表){   //30*0.8  = 24
let 坐标 = Math.floor( Math.random() * 列表.length ); //向下取整(小于等于她的最接近他的整数)
return 列表[坐标]; //数组中某一句
};

上面的函数用于从个数组中取句子。

传入的参数就是上面定义的数组的名字,同时返回一句。

function 随便取一个数(最小值 = 0,最大值 = 100){
let 数字 = Math.random()*( 最大值 - 最小值 ) + 最小值; //math返回一个0.0-1.0之间的随机数
return 数字;
}

上面的函数用于生成1-100的随机数。后面会讲到他的作用

function 来点名人名言(){
let 名言 = 随便取一句(名人名言) //名人名言是数组名
名言 = 名言.replace("曾经说过", 随便取一句(前面垫话) ) //前面垫话和后面垫话均是数组名
名言 = 名言.replace("这不禁令我深思", 随便取一句(后面垫话) )
return 名言;
}

该函数的作用就和他的名字一样,取一条名人名言。(会用到“随便取一句”这个函数。

我们可以看到,在他的函数里面,当他取到名人名言的时候,对这个句子的前面垫话和后面垫话进行了替换。保证了名人名言某种程度地多样性。(名人名言中的每句名人名言都有“曾经说过”和“这不禁令我深思”);

function 来点论述(){
let 句子 = 随便取一句(论述);
句子 = 句子.replace(RegExp("主题", "g"),主题); //g表示全局匹配 //使用正则进行替换,有点不懂
return 句子;
}

上面的函数用于 提取“论述”。

在提取到“论述”后,该函数使用正则对每个论述中的“主题”两字用读者输入的主题变量进行了替换。

也就是说,我们输入的关键词全部都会集中在这个函数生成的论述中。

function 增加段落(章节){
if(章节[章节.length-1] === " "){
章节 = 章节.slice(0,-2) //去掉章节后面的多余的字符 ,便于后面再后面增加句号。
}
return "  " + 章节 + "。 "
}

该函数用于“增加段落”。

对“章节”进行缩进和去掉末尾的空格,并加上句号。

核心函数

function 生成文章(){
let 文章 = []
for(let 空 in 主题){ //遍历字符串的每个元素(可能没有用到空,他只是用于控制循环的次数
let 章节 = "";
let 章节长度 = 0; //章节长度值得是字符的个数
while( 章节长度 < 6000 ){
//这个循环并不是只添加一个段落,当循环结束后会添加很多个段落。
//当添加的文字总数达到6000时会跳出循环,
let 随机数 = 随便取一个数();
if(随机数 < 5 && 章节.length > 200){
章节 = 增加段落(章节); //增加章节(章节长度>200时就添加章节了)。
文章.push(章节);
章节 = ""; //<5的随机数进行的操作 //有很小的几率添加到文章中
}else if(随机数 < 20){
let 句子 = 来点名人名言();
章节长度 = 章节长度 + 句子.length;
章节 = 章节 + 句子; //>5 且<20的随机数进行的操作 //添加名人名言:有五分之一的几率
}else{
let 句子 = 来点论述();
章节长度 = 章节长度 + 句子.length;
章节 = 章节 + 句子; //大于等于20的随机数进行的操作
}
}
章节 = 增加段落(章节);
文章.push(章节);
}
return 文章.join("\n");
}

我们会很快注意到这个有点复杂的函数中的那一个while循环,我们先来看她。

while( 章节长度 < 6000 )

这里的判断条件刚开始迷惑了我很久,让我一直以为这是在控制段落的字符数,其实不是的,她是控制本次生成段落的总字数(也就是说这个循环执行一次会生成很多的段落,并且他们的总字符数是6000(不一定一定是6000))。

我们在看while外面的那个for循环:

for(let 空 in 主题)

“主题”是一个字符串,这个循环就是遍历主题中的每一个字符,遍历的次数就是这个for循环执行的次数,也就是他内部的(我们上面提到的)while循环执行的次数。

那么我么现在就可以知道了一件很重要的事情了:生成文章的总字数 = 输入的字符数*6000 (大约)。

*************************************************************

while中有三个if else

他们通过生成的随机数控制文章中名人名言和论述所占的部分(这是个令我很惊讶的算法)。

最后,是程序的启动开关

console.log(生成文章())

​ 2019年11月6日晚 20:52

【狗屁不通文章生成器】代码分析 (javaScript)的更多相关文章

  1. “狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作

    一.垃圾文字生成器介绍 最近在浏览GitHub的时候,发现了这样一个骨骼清奇的雷人项目,而且热度还特别高. 项目中文名:狗屁不通文章生成器 项目英文名:BullshitGenerator 根据作者的介 ...

  2. JQuery html API支持解析执行Javascript脚本功能实现-代码分析

    JQuery html用法(功能类似innerHTML) 开发中需要使用Ajax技术来更新页面局部区域, 使用的方法是ajax获取html代码段(字符串),然后将这个html代码段作为参数,传入目标D ...

  3. 几篇QEMU/KVM代码分析文章

    QEMU/KVM结合起来分析的几篇文章,代码跟最新的版本有些差异,但大体逻辑一样,写得通俗易懂.我把链接放这里主要是为自己需要查看时调转过去方便,感谢作者的付出! QEMU Source Code S ...

  4. 分析JavaScript代码应该放在HTML代码哪个位置比较好

    本文总结了多种放置JS代码的方法,需要的朋友可以参考下 在哪里放置 JavaScript 代码? 通常情况下,JavaScript 代码是和 HTML 代码一起使用的,可以将 JavaScript 代 ...

  5. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  6. iOS 使用UIWebView把oc代码和javascript相关联

    首先请参看一篇文章,作者写的很明白,请参看原地址 http://blog.163.com/m_note/blog/static/208197045201293015844274/. 其实,oc和js的 ...

  7. AngularJS PhoneCat代码分析

    转载自:http://www.tuicool.com/articles/ym6Jfen AngularJS 官方网站提供了一个用于学习的示例项目:PhoneCat.这是一个Web应用,用户可以浏览一些 ...

  8. XSS原理及代码分析

    前言 XSS又叫跨站脚本攻击,是一种对网站应用程序的安全漏洞攻击技术.它允许恶意用户将代码注入网页,其他用户在浏览网页时就会受到影响.XSS分为三种:反射型,存储型,和DOM型.下面我会构造有缺陷的代 ...

  9. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

随机推荐

  1. day_14 匿名函数与内置函数连用 作业题

    ''' 要求: 从文件中取出每一条记录放入列表中,列表的每个元素都是` {'name':'egon','sex':'male','age':18,'salary':3000}`的形式 ''' all_ ...

  2. Scala传递参数遇到的坑

    1.方法中的参数全为val型. 例: def insertMap(map:=>Map[String,Int]):Unit={ map+=("b"->2)    //报错 ...

  3. python运算符Ⅵ

    Python成员运算符 除了以上的一些运算符之外,Python还支持成员运算符,测试实例中http://www.xuanhe.net/包含了一系列的成员,包括字符串,列表或元组. 实例(Python ...

  4. 16. ClustrixDB Rebalancer

    管理平衡 Clustrix Rebalancer被设计成自动作为后台进程运行,以便跨集群重新平衡数据.介绍如何配置和监视rebalancer,但是大多数部署不需要用户干预. Rebalancer主要通 ...

  5. 定时器的写法 winform

    private void timer1_Tick(object sender, EventArgs e) { if ( tttttflag) { Action action = SyncCompany ...

  6. LOJ #539. 「LibreOJ NOIP Round #1」旅游路线 倍增floyd + 思维

    考试的时候是这么想的: 求出每一个点花掉 $i$ 的花费向其他点尽可能走的最长距离,然后二分这个花费,找到第一个大于 $d$ 的就输出$.$然而,我这个记忆化搜索 $TLE$ 的很惨$.$这里讲一下正 ...

  7. JUnit——单元测试步骤

    步骤: 1. New Package(一般命名为*.Test,测试类与开发类放在不同的包中)2. New JUnit Text Case(一般命名为*Test)3. 选择需要测试的方法 4. 可以下载 ...

  8. C# 前台和后台POST提交信息的实现方法

    一.系统A(官网)与系统B(第三方支付平台)数据交换的方式 1.1  页面浏览器方式:系统A以构造Form表单的方式,通过系统A客户的浏览器重定向到系统B(向系统B发送请求),B系统完成交易后,将交易 ...

  9. Ajax监测开始执行及结束执行

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  10. 算法中Amortised time的理解

    ref:http://stackoverflow.com/questions/200384/constant-amortized-time 如果非要翻译成中文,我觉得摊算时间或均摊时间(注意,它和平均 ...