自定義分詞起始規則實現關鍵詞全詞高亮專案實戰(全語種通吃)
本站內容均來自興趣收集,如不慎侵害的您的相關權益,請留言告知,我們將盡快刪除.謝謝.
背景
最近有BU給我們這邊提了一個需求,希望我們能改進現有的郵件關鍵詞匹配功能,希望能支援英文的全詞匹配。
目前前端頁面是會對後臺配置的關鍵詞進行高亮顯示的,只不過算是 模糊匹配 了,也就是說如果關鍵詞配的是 book
,郵件中的 booked
中的 book
也會高亮,而這並不是BU希望的。
現狀
我看了下原來高亮功能的具體實現
export function escapeHtml(text) { var map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ' ', }; return text.replace(/[&<>"']/g, function(m) { return map[m]; }); } // 搜尋html關鍵字並高亮 export function htmlKeyWordHighlight(parentNode, keyWards, color = 'yellow') { if (keyWards === void 0 || !parentNode) return; for (var i = 0; i < parentNode.childNodes.length; i++) { var child = parentNode.childNodes[i]; if (child.nodeType == 3 && child.data.indexOf(keyWards) != -1) { var newChild = document.createElement('span'); var tagStripper = new RegExp(keyWards, 'g'); newChild.innerHTML = escapeHtml(child.data).replace( tagStripper, `<span>` + keyWards + '</span>', ); parentNode.replaceChild(newChild, child); } else { htmlKeyWordHighlight(child, keyWards, color); } } }
打出這 keyWards 的我猜測用的編輯器多半是vscode或者是個心態特別好的老哥,但凡是idea系列的那波浪線就容易讓人有強迫症。
用法大致就是這樣 htmlKeyWordHighlight(document.body, "book","#FFB10A")
,這樣就會把 body
上所有包含 book
的字串高亮起來了。
方法裡面執行的是字串的replace操作,以 book
的替換為例,實際執行的是 "A guest who booked xxx".replace(/book/g, "***")
操作,此時是不會顧及是否是全詞匹配的,只要匹配上都會替換的。
常規解決方案——正則表示式\b
既然之前用的是正則表示式,我們優先考慮能不能優化下正則表示式來完成需求。
如果只是想簡單的應對英文的話,我們用上正則表示式的元字元 \b
就行,它代表著單詞的開頭或結尾,也就是單詞的分界處。 更精確的說法, \b
匹配這樣的位置:它的前一個字元和後一個字元不全是(一個是,一個不是或不存在) \w
,我們可以簡單的理解 \b
等識別出一個分詞的開始和結束。
很符合英文單詞全詞匹配,可以測試一下。 "A guest who booked xxx".replace(/\bbook\b/g, "***")
。
帶不帶 \b
效果很明顯,客戶提的需求也就算滿足了。
終極解決方案——逐詞匹配
如果想對中文等非英文語種進行類似的分詞用 \b
就不行了,我們也沒法更換 \b
的識別機制。
我們試著自己實現下,對潛在的目標文字進行逐詞匹配就行。
記得首先要確定潛在目標文字,縮小逐詞匹配的範圍。
export function htmlKeyWordHighlight(parentNode, keyword, color = 'yellow') { if (keyword === void 0 || !parentNode) { return; } for (let i = 0; i < parentNode.childNodes.length; i++) { let child = parentNode.childNodes[i]; if (child.nodeType === 3 && child.data.indexOf(keyword) !== -1) { let newChild = document.createElement('span'); newChild.innerHTML = keyWordPreciseReplacer(escapeHtml(child.data), keyword, `<span>` + keyword + '</span>' ); parentNode.replaceChild(newChild, child); } else { htmlKeyWordHighlight(child, keyword, color); } } } /** * 根據分詞規則精準替換關鍵詞 * @param keyword * @param target * @param replaceText * @returns {*} */function keyWordPreciseReplacer(keyword, target, replaceText) { function isOver(str) { // 根據常用分詞標點符號和空格進行分詞 const regStr = '[。!!??,,\\.\\s()()]'; return new RegExp(regStr).test(str); } let index = 0; let targetIndex = 0; const result = []; const text = keyword + ' '; // 結尾新增一個空格方便isOver判斷 for (let i = 0; i < text.length; i++) { const str = text[i]; if (isOver(str)) { // text新的分詞開始 if (targetIndex === target.length) { // target也剛好全匹配 result.push([index, i - target.length]); index = i; } targetIndex = 0; // 重新計數 } else if (str === target[targetIndex]) { targetIndex++; // 繼續匹配 } else { targetIndex = -1; // 本輪分詞已沒戲,等待下輪分詞 } } result.push([index]) return result.reduce((acc, curr) => acc + keyword.slice(...curr) + (curr.length > 1 ? replaceText : ''), ''); }
註釋寫的算比較詳細了。
isOver
裡面判斷的分詞的依據可能會有遺漏,後續可能動態調整,建議寫到配置檔案裡面。
現在可沒有用 \b
了哦。
現在我們搞箇中文測試下,我們把關鍵詞設定為 我
和 後續
,把分詞的正則表示式裡面加入 司會
,即 const regStr = '[。!!??,,\\.\\s()()司會]';
。
預期的效果是: 我們
裡面的 我
不需要高亮,而 我司
的 我
需要高亮,同時 後續
也需要高亮,因為 司
和 會
代表分詞結束。
高亮結果符合預期,後期無非是遺漏了分詞符號(比如、——),需要改下配置來調整正則即可。
總結
如果場景較為單一,僅需要支援英文的話,直接用 \b
即可,如果需要特別卷的話,那就用逐詞匹配吧。
- 全自動資料建模平臺打造建模新正規化,人人都能成為資料科學家 | 愛分析調研
- 如何用DBSCAN聚類模型做資料分析?
- 精準使用者畫像!商城使用者分群2.0!
- Test time adaptation方法總結
- 超精準!AI 結合郵件內容與附件的意圖理解與分類!
- AI加速器與機器學習演算法:協同設計與進化
- 使用SINet進行偽裝目標檢測
- ECCV 2022 Oral | 理解藝術字:用於場景文字識別的角點引導Transformer
- AI醫療高精尖!基於AI的新葯研發!
- 谷歌&北大擴散模型(Diffusion Model)首篇綜述-Diffusion Models: A Comprehensive Survey of Meth…
- 協同過濾演算法——基於物品(Item)
- MLOps對比DevOps:有什么區別?
- CVPR 2022 | UniDet:通用的多資料集目標檢測
- ECCV 2022 | k-means Mask Transformer
- IS 2022 | 位元組AI Lab聯合南科大提出:利用偽標註資料提升端到端S2ST
- 自定義分詞起始規則實現關鍵詞全詞高亮專案實戰(全語種通吃)
- 電商搜尋全鏈路(PART II)Query理解
- 機器學習分類問題:九個常用的評估指標總結
- 簡單的文字分類任務:不借助Trainer實現
- Macbook Pro M1晶片使用Pytorch進行深度學習小試