前面已经初始化了项目,同时完成了ES Modules的配置。接下来我们开始正式进入代码层面的学习。
语料库
首先在article目录下建立 resources 目录 ,在resources下建立一个data.json的json文件。我们这个demo的核心就是通过随机取一些语料库的文字来组成一篇文章。
data.json如下:
{
"title": [
],
"famous":[
"爱迪生{{said}},天才是百分之一的勤奋加百分之九十九的汗水。{{conclude}}",
"查尔斯·史{{said}},一个人几乎可以在任何他怀有无限热忱的事情上成功。{{conclude}}",
"培根说过,深窥自己的心,而后发觉一切的奇迹在你自己。{{conclude}}"
],
"bosh_before": [
"既然如此,",
"那么,",
"我认为,"
],
"bosh":[
"{{title}}的发生,到底需要如何做到,不{{title}}的发生,又会如何产生。 ",
"而这些并不是完全重要,更加重要的问题是,",
"{{title}},到底应该如何实现。 "
],
"conclude":[
"这不禁令我深思。 ",
"带着这句话,我们还要更加慎重的审视这个问题: ",
"这启发了我。"
],
"said":[
"曾经说过",
"在不经意间这样说过",
"说过一句著名的话"
]
}
接下来开始尝试编写JavaScript代码
随机模块(初版)
在项目根目录下创立一个lib目录,然后在lib目录下创建一个random.js的js文件,用于随机选取。
首先我们需要编写一个函数用于随机数的选取。
function randomInt(min,max) {
const p = Math.random();
return Math.floor(min * (1 - p) + max * p);
}
上述函数可以获取min 到 max间的随机整数。
接下来我们再写一个随机选取句子的函数,当fs模块读取完data.json后,将dataStr数组传给这个函数,就可以通过返回数组元素的内容完成句子的读取。(当然这个随机模块也有一点点小问题,我参考了大佬的代码之后做了一些优化与处理,后面再说)
接下来我们做个测试,先导入fs模块然后尝试通过fs.readFile()进行data.json的读取,因为读取出来的数据是JSON,所以我们还需要通过JSON.parse()来进行解析。该部分的全部代码如下:
import fs from 'fs';
fs.readFile('../resources/data.json',{encoding:"utf-8"},(err,dataStr)=>{
if (err) {
console.log(err);
}
else {
const array = JSON.parse(dataStr);
console.log(array);
}
})
我们打印出的array发现是个数组,接下来我们传入之前的randomPick()函数中
import fs from 'fs';
\
function randomInt(min,max) {
const p = Math.random();
return Math.floor(min * (1 - p) + max * p);
}
\
function randomPick(arr) {
const index = randomInt(0,arr.length);
return arr[index];
}
\
fs.readFile('../resources/data.json',{encoding:"utf-8"},(err,dataStr)=>{
if (err) {
console.log(err);
}
else {
const array = JSON.parse(dataStr);
console.log(randomPick(array.famous));
}
})
我们发现可以随机打印出一些话,比如如下
查尔斯·史{{said}},一个人几乎可以在任何他怀有无限热忱的事情上成功。{{conclude}}
爱迪生{{said}},天才是百分之一的勤奋加百分之九十九的汗水。{{conclude}}
.......
大概如上
模块化
作为一名开发者,我们要考虑到很多因素,比如代码的工整性,规范性,还要尝试对我们写的一些代码进行模块化,便于复用。
我们将random.js中的代码进行模块化并导出(因为fs读取并调用randomPick()函数是用于给读者演示的,所以这里删掉这些),代码如下:
export function randomInt(min,max) {
const p = Math.random();
return Math.floor(min * (1 - p) + max * p);
}
export function randomPick(arr) {
const index = randomInt(0,arr.length);
return arr[index];
}
接下来我们如果要在其他地方引用这两个函数只需要import导入即可。
不足及解决
问题一
在随机选取的时候,可能会多次选取到同一条语句,虽然是狗屁不通文章生成器,但是连着好几句话一模一样还是很奇怪,所以我们应该不能完全随机,如果重复选到一样的语句应该进行重新选择。
我们设置一个previous变量和一个now变量来记录两次结果。然后通过do...while来比对,再返回。
问题二
问题一的解决方案并不好,增加了选取的次数。参考月影老师的文章,这里我们提出最终的解决方案
我们这里选择用过程抽象的方法把它改成一个高阶函数
export function randomInt(min,max) {
const p = Math.random();
return Math.floor(min * (1 - p) + max * p);
}
export function randomFun(arr) {
areReal = [...arr];
function randomPick() {
const right = areReal.length - 1;
const index = randomInt(0,right);
const pick = areReal[index];
[areReal[index],areReal[right]] = [areReal[right],areReal[right]];
return pick;
}
randomPick();
return randomPick;
}
最终版本如上,代码略微有一些复杂。randomInt()的功能上面已经手把手写过了,这里就不多赘述了。
高阶函数randomFun()中,首先copy了数组副本areReal,接下来对数组的操作都是针对副本数组的,不会改变原数组。然后又写了一个randomPick()函数,从第一位到最后一位的前一位进行随机抽取,抽取完的放到最后一位,这样就可以避免两次选到同一条语句。函数写完后,先调用一次,这样首次末尾元素就是随机的,充分保证了随机性。
基于node.js开发的文章生成器(二、语料库的读取与生成句子)就告一段落了,我们有了上述函数就可以随机抽取语句了。第三部分明天继续。