首先介绍下freestyle外挂:这是一个根据韵脚,以词搜词的软件。

看着一堆韵脚一致的词 + 一点自己的想象力 = 让你的freestyle开启了外挂

用下面一个例子来说明使用场景

这是我一次去快餐店吃饭拍的照片

说简单点儿就是在我软件里搜“老娘舅”,你搜到的一堆词里有“要讲究”。

我写了一个微信小程序,总共两个页面,看图

图一.韵脚搜词界面
图二.搜索“灵魂”后韵脚搜索结果页面
图三.扫描(或长按)二维码可体验小程序,logo是一个小鸭子,押韵的鸭,灵感来自女友

微信小程序实现没太多的技术点,就俩静态页面 和 一个接口请求,暂不赘述,如果你感兴趣想看前端源码的话,在评论里留下邮箱,我会一一发给你们的。

恩,前端是这个样子,那么我们来看后台,就是标题所谓的“不到20行代码写一个freestyle外挂后台”。后台用了一个node.js框架koa,代码非常的简洁,支持async/await语法特性,整个项目除了配置文件,源码就这一个不到20行代码的文件,先看代码

图四.传说中不到20行代码的后台

恩 ,乍一看的确加上注释,算起来代码也没到20行,但感觉还是被作者标题党了。

这感觉就像是去电信局拉了条100兆宽带,实际下载速度却只有10M/秒左右。【括号】(1B = 8b ,100Mbps = 12.5MB/秒)。的确,号称不到20行代码的freestyle外挂后台代码里也有这么一个【括号】,也就是代码里的第四行,接下去就让我们来解开这个括号。

如各位在第四行所见,韵脚搜词逻辑实现部分被我封装成了一个 插件“free-style-plugin” ,整个插件只向外暴露一个函数 getWords(keyWord,searchCondition) ,我们只需向其传递两个参数:搜索关键词,搜索类型(全压,单压,英文),它就会向我们返回在词库中搜索到的结果。

首先,我整体地介绍一下我实现韵脚搜词这个功能的主要步骤

  1. 初始化词库,包括中文词库,英文词库。(把网上找的词库初始化成我自己定义的数据格式)
  2. 根据搜索条件,提取搜索关键词的韵脚。(中文搜索用的是韵母搜索,英文搜索用的是声母搜索)
  3. 根据搜索条件,在相应词库中搜索韵脚匹配的单词并返回

我调研后采用的几个第三方库

那就从先进步,初始化词库讲起

/**
 * 初始化中文词库
 */
function initDictYunMu() {
  var promise = new Promise( (resolve, reject) => {
    fs.readFile(__dirname + '/data/dict.txt', 'utf-8', function(err, data) {
        if (err) {
            console.error(err);
        } else {
            var start = new Date().getTime();
            /**
             * txt中的词库转换成一个数组
             */
            var arrRaw = data.split('\n');
            /**
             * [arr 数据清洗之后的词库]
             */
            var arr = [];
            arrRaw.forEach(item => {
                var itemSplit = item.split(' ')
                /**
                 * [构建一个新的对象push进数组]
                 * @name 单词
                 * @weight 使用频率
                 * @yunMu 韵母
                 */
                arr.push({ name: itemSplit[0], weight: itemSplit[1], yunMu: getYunMu(itemSplit[0]) });
            })
            /**
             *  根据单词的 使用频率 & 单词的长短 排序
             *  去除单个字的结果 ,用来单压搜索
             */
            arr = arr.sort((a, b) => (a.weight - b.weight)).sort((a, b) => (a.name.length - b.name.length)).filter(value => { return value.name.length > 1 })
            var end = new Date().getTime();
            // console.log(`处理词库220626多词共花费${(end-start)/1000}秒`);
            // console.log(arr);  
            dict = arr;
            resolve()
        }
    });
  })
  return promise
}

用fs.readFile读取txt词库文件,根据分隔符把数据转换成数组,遍历数组把数组内容转换成我们想要的格式,比如 {name:'外挂',weight: 3, yunMu: ',ai,ua'},再根据词语的使用频率和单词长短排序。 初始化中文词库(220626个词)大概要花7秒钟左右

其实刚开始的时候,(因为上面提到的初始化词库是异步的,大概需要7秒时间),npm插件暴露了两个函数: init() , getWords() 。在后台启动的时候先执行 init() ,拦截到路由 /findSameRhymeWords 就执行 getWords()。 但后来发现这样实现有弊端:1.增加插件的使用成本。2.在后台词库未初始化完成的时候请求会报错。

所以代码进行如下改造

  • 初始化的时候把这个值缓存下来(也就是代码中的全局变量 dict),之后每次请求进来如果缓存有值就在这个变量里搜索就好了,没值就初始化词库。
  • 这里我用了 promise 的写法,让初始化中文词库,初始化英文词库,搜词以比较简洁的形式 同步执行 ,也避免了所谓的回调地狱。

所以npm最终只暴露一个函数: getWords()

第二步,提取搜索关键词的韵脚

这个步骤主要用到的是 上文提到的 pinyin 库,这个库可根据输入中文拿到 中文对应的拼音,声母,虽然没有直接的函数去拿关键词的韵母,但通过(全拼 - 声母)我们可以自己得出关键词的韵母。

提取韵脚

第三步,搜索韵脚匹配的单词

中文搜词,遍历整个缓存的词库 ,用indexOf去匹配词,并判断单词末端匹配。

中文搜词

英文搜词,遍历整个词库后,我这边采用正则去匹配,正则可能需要用一个例子解释下:比如说我搜索一个中文 “白头发” ,然后我取到 声母 “btf”,形成正则“B.*T.*F”,然后去英文词库匹配 发音类似的词,比如就能匹配到结果:“ beautiful”。(目前这个功能正处于beta阶段,搜索方式应该还得优化)

英文搜词

软件的细节方面介绍完了,已发布至npm,欢迎各位安装使用

$ npm install free-style-plugin

你也可以参照上面【图四】后台的写法用不到二十行的代码搭建一个韵脚搜词后台,当然如果你对插件源码感兴趣,可以访问 free-style-plugin源码git地址 nigulasikk/freeStylePlugin ,欢迎各位star,fork,指教。

部署中遇到的其他问题

  1. node.js环境。先更新node.js至比较新的版本,如(v8.2.1)
  2. 服务器gcc版本。本地调试都好好的,上服务器发现不行,最后锁定错误发现需要用pinyin库里依赖的jieba词库这边需要高的gcc版本
  3. https证书。因为微信小程序服务端必须是https的,所以得升级证书。 Let's Encrypt 是一个比较有名的免费证书,里面找了一个能自动升级centos系统对应证书并注入nginx配置的傻瓜式方案: Certbot

最后

夏天《中国有嘻哈》很火的时候,我就跟身边的人吹牛逼说我要写这么一个软件,但一直没好好写。现在快半年过去了,正好有点儿时间,就不让吹过的牛逼随青春一笑了之了。

网上看到一句蛮有道理的话,我记了下来: “不要为了押韵而失去歌词的意义”

但我想说: “开启freestyle外挂后,punchline中歌词意义和押韵是可以完美融合的”。

最后的最后

我是不懂音乐的,就先做了这么个玩具, 如果有这方面研究很先进的朋友,欢迎联系我qiankaijie1024@gmail.com,提些建议,我提供免费改代码服务哈!