node实操:使用node制作文章生成器生成文章

前言

在上节课的内容中我们学习了node.js的基础理论知识,今天也是话不多说,我们直接实操一个小功能------文章生成器,来熟悉使用node的语法和模块

初始化结构

  • 使用npm init -y 初始化生成文件,在生成的package.json文件中添加 "type": "module",使得我们能够使用ESM和Common.js语法

  • 新建curpus文件夹,在里面新建data.json文件作为我们的语料库。数据已经准备好。

  • 新建lib文件,便于我们封装一些函数。新建output,便于观察我们的输出结果。添加入口文件index.js

实战

读取数据

在index.js中可以通过 readFileSync() 读取到data中的数据。

js 复制代码
import fs from 'fs';

const content = fs.readFileSync('./curpus/data.json', 'utf8');

console.log(content);

考虑到项目压缩时可能带来的路径改变,ESM提供了 fileURLToPath 来获取文件所在的绝对路径。

绝对路径

当将项目部署在服务器或在开发过程中需要在其他开发者电脑中访问文件时,绝对路径显得尤其重要。如何访问当前文件的绝对路径?

  1. url 中引入 fileURLToPath

可以将 file: URL 转换为文件系统的路径。在ESM中,可以通过 import.meta.url 访问当前模块的URL,。然后使用 fileURLToPath 将这个URL转换为文件系统的路径

  1. path 中引入 dirname,resolve

dirname 可以访问当前文件所在的文件夹,再通过resolve拼接你想访问的文件可以得到完整的绝对路径。

优化改进后的代码如下:

js 复制代码
import fs from 'fs';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';

const url = import.meta.url;
const path = resolve(dirname(fileURLToPath(url)), 'curpus/data.json')
const data = fs.readFileSync(path, 'utf8');

console.log(path);

在这里我们可以通过 ||JSON.parse(data)||来将数据转换为对象。

将数据转换为对象:

实现两个功能

为了生成文章我们需要封装两个函数实现两个功能

随机选取内容的模块 random.js

1. 生成随机整数

  • Math.random() * (max - min + 1) 生成一个 [0, max - min + 1) 之间的随机数(因为 Math.random() 生成的是 [0, 1) 的数,乘以 max - min + 1 后范围变为 [0, max - min + 1))。
  • 通过 Math.floor() 向下取整,我们得到一个在 [0, max - min] 范围内的整数。
  • 最后,通过加上 min,我们将范围调整到 [min, max]。
js 复制代码
export function randomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

2. 确保选择的元素不重复

从某个数组 arr 中随机选择一个元素,确保这个元素不会与上一次选择的元素(lastPicked)相同。

这段代码定义了一个名为 createRandomPicker 的函数,它接受一个数组 arr 作为参数,并返回一个名为 randomPick 的函数。

randomPick函数的作用:

  • 首先,计算数组的长度减一(len),因为数组索引是从 0 开始的,所以最后一个元素的索引是 length - 1

  • 然后,使用 randomInt 函数来生成一个介于 0 和 len 之间的随机整数作为索引(index)。

  • 接下来,使用数组解构赋值将随机索引处的元素与最后一个元素交换位置。这样,每次调用 randomPick 时,都会将最后一个元素"移动到"随机索引处,并返回它。

js 复制代码
export function createRandomPicker(arr) {
    // 数组复制,使得更改数组不影响原数据
    arr = [...arr]
   // 实现随机选择逻辑
    function randomPick() {
    // 数组下标长度
        const len = arr.length - 1
        // 控制index的范围
        const index = randomInt(0, len);
        
        [arr[index], arr[len]] = [arr[len], arr[index]]
        return arr[index]
    }
    randomPick()  // 放弃第一次结果
    return randomPick
}

重组语料库

1. 替换文本

这个函数 sentence 的作用是根据提供的两个参数来生成和修改文本句子。它首先调用一个函数(pick)来获取一个初始的句子(或字符串),然后遍历一个替换器对象(replacer),在该对象中定义了需要替换的占位符( {{key}})以及它们应该被替换成的内容或生成内容的函数。

函数的工作流程如下:

  1. 获取初始句子 :通过调用 pick() 函数获取一个初始的句子(或字符串),这个函数预期会返回一个包含占位符(如 {{key}})的字符串。

  2. 遍历替换器对象replacer 是一个对象,其属性名对应要替换的占位符中的 key(去掉 {{}}),属性值则是替换后的内容或一个函数,该函数在被调用时返回替换内容。

  3. 执行替换 :对于 replacer 中的每一对键值,函数使用正则表达式来查找初始句子中所有匹配的占位符({{key}}),并将它们替换为对应的值或调用对应函数后返回的值。这里使用了 g 标志来确保所有匹配的占位符都被替换,而不仅仅是第一个。

  4. 返回修改后的句子:完成所有替换后,函数返回修改后的句子。

js 复制代码
// 引入随机生成的句子
import { randomInt, createRandomPicker } from './random.js'
// 得到一个句子
function sentence(pick, replacer) {
    let ret = pick()  
    // 遍历从语料库中得到的句子,循环遍历
    for (const key in replacer) {
    // 替换数据
        ret = ret.replace(
        // 利用正则表达式,使用'g'占位符替换key
            new RegExp(`{{${key}}}`, 'g'),
            // 判断是不是函数
 typeof replacer[key] === 'function' ? replacer[key]() : replacer[key]
        )
    }
    return ret
}

2.组合文本,生成文章

定义了一个名为 generate 的函数,旨在根据提供的标题和语料库(corpus)生成一篇文章。文章由多个段落组成,每个段落的内容根据一定的规则和概率从语料库中随机选择并组合。

函数内部逻辑:

  1. 文章长度 :首先,使用 randomInt 函数(未在代码段中定义,但基于上下文,我们假设它生成一个指定范围内的随机整数)生成一个介于 minmax 之间的随机整数,作为目标文章长度(articleLenth)。

  2. 语料库处理 :从 corpus 对象中提取五个数组,并使用 createRandomPicker 函数(未在代码段中定义,但根据命名和上下文,我们假设它返回一个函数,该函数在每次调用时从给定数组中随机选择一个元素)为每个数组创建一个随机选择器(pickFamous, pickBoshBefore, pickBosh, pickConclude, pickSaid)。

  3. 生成文章 :通过一个外层 while 循环,持续生成段落直到文章的总长度达到或超过目标长度(articleLenth)。

    • 在内层循环中,首先生成一个段落的目标长度(sectionLength),范围在 100 到 300 个字符之间。

    • 然后,通过另一个 while 循环,持续向段落中添加内容直到其长度达到或超过目标段落长度。内容的添加基于一个随机数 n,该随机数决定了从哪个语料库部分选择内容:

      • 如果 n 小于 20,使用 sentence 函数(未在代码段中定义,但基于上下文,我们假设它接受一个生成器函数和一个替换器对象,并返回一个经过替换的字符串)从 famous 部分选择内容,并可能使用 saidconclude 替换器。
      • 如果 n 在 20 到 50 之间(不含50),先使用 bosh_before 部分的内容(可能带有 title 替换),然后添加 bosh 部分的内容。
      • 如果 n 大于或等于 50,只从 bosh 部分选择内容。
  4. 返回文章:当文章的总长度达到或超过目标长度时,函数返回包含所有段落的数组。

js 复制代码
// 打造函数,可传入参数文章标题和字数多少
export function generate(title, { corpus, min = 500, max = 800 }) {
// 文章长短为随机数
    const articleLenth = randomInt(min, max)
    // 提取语料库(`corpus`)中的特定字段
    const { famous, bosh_before, bosh, conclude, said } = corpus
// 为这些字段中的每一个创建随机选择器,方便从每个字段的集合中随机选择一个元素
    const [pickFamous, pickBoshBefore, pickBosh, pickConclude, pickSaid]
        = [famous, bosh_before, bosh, conclude, said].map(createRandomPicker)
// 定义文章空数组
    const article = []
// 文章初始长度为0
    let totalLength = 0
// 文章字数不够时不停生成
    while (totalLength < articleLenth) {  
// 段落为空字符串
        let section = ''
// 段落长度随机100到300字之间
        const sectionLength = randomInt(100, 300)
// 不达标循环生成
        while (section.length < sectionLength) { 
        // 假设有随机数0到100
            const n = randomInt(0, 100)
       // 段落构成随机组合
            if (n < 20) {
          section += sentence(pickFamous, 
      { said: pickSaid, conclude: pickConclude })
            } else if (n < 50) {
                section += sentence(pickBoshBefore,
                { title }) + sentence(pickBosh, { title })
            } else {
                section += sentence(pickBosh, { title })
            }
        }
        // 总长度就是段落的长度
        totalLength += section.length
        // 把这些段落放进文章中
        article.push(section)
    }
    return article
}

生成文本index.js

回到index.js中

  1. 引入打造的方法
  2. 打造函数读取绝对路径下的语料库
  3. 选取文章标题
  4. 组合文章
  5. 将文本写入文件夹中
js 复制代码
import fs from 'fs'
import { fileURLToPath } from 'url'
import { dirname, resolve } from 'path'
// 引入随机生成的文章
import { generate } from './lib/generator.js'
// 引入从语料库中随机选择的句子
import { createRandomPicker } from './lib/random.js'
// 读取当前脚本的绝对路径,将数据以对象形式返回
function loadCorpus(src) {
    const url = import.meta.url  
    const path = resolve(dirname(fileURLToPath(url)), src)
    const data = fs.readFileSync(path, { encoding: 'utf8' })
    return JSON.parse(data)
}
const corpus = loadCorpus('curpus/data.json')
// 选取文章标题
const pickTitle = createRandomPicker(corpus.title)
const title = pickTitle()
// 生成文章
const article = generate(title, { corpus })
// 写入文章
fs.writeFileSync(`./output/${title}.txt`, article.join(''));

最后,文本生成,打开我们事先准备好的output文件夹,发现其中多出几个文件

恭喜!文章生成成功!

相关推荐
王哲晓2 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4115 分钟前
无网络安装ionic和运行
前端·npm
理想不理想v6 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云16 分钟前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:1379712058718 分钟前
web端手机录音
前端
齐 飞24 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
暮毅29 分钟前
10.Node.js连接MongoDb
数据库·mongodb·node.js
LunarCod41 分钟前
WorkFlow源码剖析——Communicator之TCPServer(中)
后端·workflow·c/c++·网络框架·源码剖析·高性能高并发
神仙别闹41 分钟前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
码农派大星。1 小时前
Spring Boot 配置文件
java·spring boot·后端