總結(jié)Electron項(xiàng)目中全文搜索遇到的坑

最近在完善Electron項(xiàng)目中的全文搜索功能,遇到了不少坑,大多與正則有關(guān)。因正則這塊兒一直比較弱,干脆總結(jié)一下。

Sql通配符

全文搜索必然會用到sql查詢中的關(guān)鍵字like,于是不用想就能寫出下面的查詢語句:

'select * FROM \'tbl_msg\' WHERE content like \'%'+key+'%\''

然后測試就反饋問題了: 在搜索的關(guān)鍵字中,帶有%,_時,會搜出很多不相干的內(nèi)容。

因?yàn)?和_是sql語句中的通配符,傳入上面的語句中,不會被識別為文本去匹配,需要添加轉(zhuǎn)義符。

因搜索的關(guān)鍵字是變量,需要將關(guān)鍵字中的通配符替換為加上轉(zhuǎn)義字符前綴,這里轉(zhuǎn)義字符可以通過ESCAPE關(guān)鍵字去定義。

// 執(zhí)行sql查詢前,替換關(guān)鍵字
const escapeTexts = ['%', '_'];
_.each(escapeTexts, item => {
  searchKey = String(searchKey).replace(new RegExp(item, 'g'), `\\${item}`);
});

`'select * FROM \'tbl_msg\' WHERE content like \'%'+key+'%\'' ESCAPE \'\\\'`

我們定義了轉(zhuǎn)義符\,對關(guān)鍵字中出現(xiàn)的%_進(jìn)行替換。

通訊錄搜索

全文搜索包含了對本地?cái)?shù)據(jù)庫和服務(wù)器中用戶列表的搜索,這種搜索場景下,關(guān)鍵字中的標(biāo)點(diǎn)符號和特殊字符沒有意義,需要在搜索前進(jìn)行過濾。

// 去除文本中的特殊字符和標(biāo)點(diǎn)
 escapePunctuation(text) {
   return text.replace(/[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]/g, '');
  },

關(guān)鍵字高亮

在展示搜索結(jié)果時,需要對匹配內(nèi)容進(jìn)行高亮。在jsx中,將匹配內(nèi)容替換為html字符串即可實(shí)現(xiàn),但若只這么寫,會有諸多問題。

  • 特殊字符的轉(zhuǎn)義
    這里使用了lodash提供的escapeRegExp方法
  • 大小寫的替換
    搜索匹配時,我們應(yīng)忽略大小寫的區(qū)分,但在高亮替換時,不能直接用搜索關(guān)鍵字去替換,這樣會導(dǎo)致原文的大小寫被替換。
text = text.replace(/keyReg/gi, (keyText) => `<span class="highlight">${keyText}</span>`)
  • html轉(zhuǎn)jsx
    因關(guān)鍵字高亮?xí)⑽谋巨D(zhuǎn)換為帶有html的字符串,在寫jsx時,需要使用dangerouslySetInnerHTML屬性,這樣顯然不利于封裝和組件復(fù)用。建議通過htmr之類的庫進(jìn)行直接轉(zhuǎn)換,生成react node。
  • 文本中特殊字符轉(zhuǎn)換
    使用htmr前,需要考慮待替換文本中有特殊字符的可能,尤其是<>,例如<message>123<message>這樣的文本經(jīng)htmr轉(zhuǎn)換后,jsx會將<message>識別為html標(biāo)簽,導(dǎo)致報(bào)錯。因此,高亮關(guān)鍵字的第一步應(yīng)該是替換特殊字符。
  const escapeHtml = (html) => {
    return String(html)
      .replace(/&(?!\w+;)/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#039;');
  }
  
  const convertHtmlWithSearchKey = (text, searchKey, noWrap) => {
    text = escapeHtml(text);
    const keyReg = new RegExp(escapeRegExp(searchKey), 'gi');
    text = text.replace(keyReg, (keyText) => `<span class="highlight">${keyText}</span>`);
    if (!noWrap) {
      text = text.replace(/(\r\n)|\n|\r/g, '<br>');
    }
    return convert(text);
  },
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容