首先介紹下freestyle外掛:這是一個根據(jù)韻腳,以詞搜詞的軟件。

看著一堆韻腳一致的詞 + 一點(diǎn)自己的想象力 = 讓你的freestyle開啟了外掛

用下面一個例子來說明使用場景

這是我一次去快餐店吃飯拍的照片

說簡單點(diǎn)兒就是在我軟件里搜“老娘舅”,你搜到的一堆詞里有“要講究”。

我寫了一個微信小程序,總共兩個頁面,看圖

圖一.韻腳搜詞界面
圖二.搜索“靈魂”后韻腳搜索結(jié)果頁面
圖三.掃描(或長按)二維碼可體驗(yàn)小程序,logo是一個小鴨子,押韻的鴨,靈感來自女友

微信小程序?qū)崿F(xiàn)沒太多的技術(shù)點(diǎn),就倆靜態(tài)頁面 和 一個接口請求,暫不贅述,如果你感興趣想看前端源碼的話,在評論里留下郵箱,我會一一發(fā)給你們的。

恩,前端是這個樣子,那么我們來看后臺,就是標(biāo)題所謂的“不到20行代碼寫一個freestyle外掛后臺”。后臺用了一個node.js框架koa,代碼非常的簡潔,支持async/await語法特性,整個項目除了配置文件,源碼就這一個不到20行代碼的文件,先看代碼

圖四.傳說中不到20行代碼的后臺

恩 ,乍一看的確加上注釋,算起來代碼也沒到20行,但感覺還是被作者標(biāo)題黨了。

這感覺就像是去電信局拉了條100兆寬帶,實(shí)際下載速度卻只有10M/秒左右。【括號】(1B = 8b ,100Mbps = 12.5MB/秒)。的確,號稱不到20行代碼的freestyle外掛后臺代碼里也有這么一個【括號】,也就是代碼里的第四行,接下去就讓我們來解開這個括號。

如各位在第四行所見,韻腳搜詞邏輯實(shí)現(xiàn)部分被我封裝成了一個 插件“free-style-plugin” ,整個插件只向外暴露一個函數(shù) getWords(keyWord,searchCondition) ,我們只需向其傳遞兩個參數(shù):搜索關(guān)鍵詞,搜索類型(全壓,單壓,英文),它就會向我們返回在詞庫中搜索到的結(jié)果。

首先,我整體地介紹一下我實(shí)現(xiàn)韻腳搜詞這個功能的主要步驟

  1. 初始化詞庫,包括中文詞庫,英文詞庫。(把網(wǎng)上找的詞庫初始化成我自己定義的數(shù)據(jù)格式)
  2. 根據(jù)搜索條件,提取搜索關(guān)鍵詞的韻腳。(中文搜索用的是韻母搜索,英文搜索用的是聲母搜索)
  3. 根據(jù)搜索條件,在相應(yīng)詞庫中搜索韻腳匹配的單詞并返回

我調(diào)研后采用的幾個第三方庫

那就從先進(jìn)步,初始化詞庫講起

/**
 * 初始化中文詞庫
 */
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中的詞庫轉(zhuǎn)換成一個數(shù)組
             */
            var arrRaw = data.split('\n');
            /**
             * [arr 數(shù)據(jù)清洗之后的詞庫]
             */
            var arr = [];
            arrRaw.forEach(item => {
                var itemSplit = item.split(' ')
                /**
                 * [構(gòu)建一個新的對象push進(jìn)數(shù)組]
                 * @name 單詞
                 * @weight 使用頻率
                 * @yunMu 韻母
                 */
                arr.push({ name: itemSplit[0], weight: itemSplit[1], yunMu: getYunMu(itemSplit[0]) });
            })
            /**
             *  根據(jù)單詞的 使用頻率 & 單詞的長短 排序
             *  去除單個字的結(jié)果 ,用來單壓搜索
             */
            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多詞共花費(fèi)${(end-start)/1000}秒`);
            // console.log(arr);  
            dict = arr;
            resolve()
        }
    });
  })
  return promise
}

用fs.readFile讀取txt詞庫文件,根據(jù)分隔符把數(shù)據(jù)轉(zhuǎn)換成數(shù)組,遍歷數(shù)組把數(shù)組內(nèi)容轉(zhuǎn)換成我們想要的格式,比如 {name:'外掛',weight: 3, yunMu: ',ai,ua'},再根據(jù)詞語的使用頻率和單詞長短排序。 初始化中文詞庫(220626個詞)大概要花7秒鐘左右 。

其實(shí)剛開始的時候,(因?yàn)樯厦嫣岬降某跏蓟~庫是異步的,大概需要7秒時間),npm插件暴露了兩個函數(shù): init() , getWords() 。在后臺啟動的時候先執(zhí)行 init() ,攔截到路由 /findSameRhymeWords 就執(zhí)行 getWords()。 但后來發(fā)現(xiàn)這樣實(shí)現(xiàn)有弊端:1.增加插件的使用成本。2.在后臺詞庫未初始化完成的時候請求會報錯。

所以代碼進(jìn)行如下改造

  • 初始化的時候把這個值緩存下來(也就是代碼中的全局變量 dict),之后每次請求進(jìn)來如果緩存有值就在這個變量里搜索就好了,沒值就初始化詞庫。
  • 這里我用了 promise 的寫法,讓初始化中文詞庫,初始化英文詞庫,搜詞以比較簡潔的形式 同步執(zhí)行 ,也避免了所謂的回調(diào)地獄。

所以npm最終只暴露一個函數(shù): getWords()

第二步,提取搜索關(guān)鍵詞的韻腳

這個步驟主要用到的是 上文提到的 pinyin 庫,這個庫可根據(jù)輸入中文拿到 中文對應(yīng)的拼音,聲母,雖然沒有直接的函數(shù)去拿關(guān)鍵詞的韻母,但通過(全拼 - 聲母)我們可以自己得出關(guān)鍵詞的韻母。

提取韻腳

第三步,搜索韻腳匹配的單詞

中文搜詞,遍歷整個緩存的詞庫 ,用indexOf去匹配詞,并判斷單詞末端匹配。

中文搜詞

英文搜詞,遍歷整個詞庫后,我這邊采用正則去匹配,正則可能需要用一個例子解釋下:比如說我搜索一個中文 “白頭發(fā)” ,然后我取到 聲母 “btf”,形成正則“B.*T.*F”,然后去英文詞庫匹配 發(fā)音類似的詞,比如就能匹配到結(jié)果:“ beautiful”。(目前這個功能正處于beta階段,搜索方式應(yīng)該還得優(yōu)化)

英文搜詞

軟件的細(xì)節(jié)方面介紹完了,已發(fā)布至npm,歡迎各位安裝使用

$ npm install free-style-plugin

你也可以參照上面【圖四】后臺的寫法用不到二十行的代碼搭建一個韻腳搜詞后臺,當(dāng)然如果你對插件源碼感興趣,可以訪問 free-style-plugin源碼git地址 nigulasikk/freeStylePlugin ,歡迎各位star,fork,指教。

部署中遇到的其他問題

  1. node.js環(huán)境。先更新node.js至比較新的版本,如(v8.2.1)
  2. 服務(wù)器gcc版本。本地調(diào)試都好好的,上服務(wù)器發(fā)現(xiàn)不行,最后鎖定錯誤發(fā)現(xiàn)需要用pinyin庫里依賴的jieba詞庫這邊需要高的gcc版本
  3. https證書。因?yàn)槲⑿判〕绦蚍?wù)端必須是https的,所以得升級證書。 Let's Encrypt 是一個比較有名的免費(fèi)證書,里面找了一個能自動升級centos系統(tǒng)對應(yīng)證書并注入nginx配置的傻瓜式方案: Certbot 。

最后

夏天《中國有嘻哈》很火的時候,我就跟身邊的人吹牛逼說我要寫這么一個軟件,但一直沒好好寫?,F(xiàn)在快半年過去了,正好有點(diǎn)兒時間,就不讓吹過的牛逼隨青春一笑了之了。

網(wǎng)上看到一句蠻有道理的話,我記了下來: “不要為了押韻而失去歌詞的意義”

但我想說: “開啟freestyle外掛后,punchline中歌詞意義和押韻是可以完美融合的”。

最后的最后

我是不懂音樂的,就先做了這么個玩具, 如果有這方面研究很先進(jìn)的朋友,歡迎聯(lián)系我qiankaijie1024@gmail.com,提些建議,我提供免費(fèi)改代碼服務(wù)哈!