多关键词匹配

80 阅读3分钟

无脑的需求

又是一个编排的需求来了,我需要一个搜索框,百度那样的,你看着办吧。(手打黑人问号)
做不出来,简单点!!!!!
好的!我需要一个关键词匹配的输入框,以特定符号作为分割,对返回的数据做全文高亮显示。

以上就是一个需求的诞生!!!如下

这是一段测试文字,需要通过关键词匹配,已测试中通过等等等等
输入关键词:测试,通过,已测试,测试中
输出匹配结果:这是一段测试文字,需要通过关键词匹配,已测试中通过等等等等

需求分析来了

首先我们想到的肯定是关键词替换然后用有了以下代码

    const text = '这是一段测试文字,需要通过关键词匹配,已测试中通过中等等等等'
    const matchArr = ['测试', '通过', '已测试', '测试中']
    const regex = new RegExp(`(${matchArr.join('|')})`, 'g')
    const highlightedText = text.replace(regex, '<em>$1</em>')
    console.log(highlightedText) // 这是一段<code>测试</code>文字,需要<code>通过</code>关键词匹配,<code>已测试</code>中<code>通过</code>等等等等

这是一段测试文字,需要通过关键词匹配,已测试通过等等等等

这样匹配的内容虽然大部分都相同,但是与我们想要的肯定不一样了啊。
这是一段测试文字,需要通过关键词匹配,已测试中通过等等等等 因为我们想要的是内容是如上内容,显然已测试中通过这个没有匹配上
所以这样是行不通的,如过只是单独的匹配这样写是没有问题的,但是多关键词这样写就会出现相连的词语重复性的问题。


现在问题已经出现了就要解决不能相连的问题了,然后我想到了leetCode中的一个算法题目,合并区间

image.png

如上,只要我能获取到下标区间,就能进行算法来合并区间,就可以解决(已测试通过)不能相连的问题了!(因为本人使用vue所以以下会出现vue代码,请自行进行优化)

mounted() {
    const needMatch = '这是一段测试文字,需要通过关键词匹配,已测试中通过等等等等'
    const keyword = '测试,通过,已测试,测试中'
    const indices = this.searchMatch(keyword, needMatch)
  }
  
   methods: {
    searchMatch(keyword, needMatch) {
      const keywordData = keyword && keyword.split(',') || [] // 当搜索为空时
      const indices = [] // 存储下标位置
      keywordData.forEach(item => {
        let index = needMatch.indexOf(item)
        while (index !== -1) { // 在整个文本中查找 item 的下标位置,直到找不到为止
          indices.push([index, index + item.length - 1])
          index = needMatch.indexOf(item, index + 1) // 接着在查找到的下标之后框框下一个
        }
      })
      return indices // [[4, 5], [20, 21], [11, 12], [23, 24], [19, 21], [20, 22]]
    }
   }

这个时候我们就已经拿到了我们想要的下标了,然后就需要合并区间了!

mounted
    const mergeIndices = this.merge(indices) // [[4, 5], [11, 12], [19, 22], [23, 24]]
methods
    merge(intervals) {
      if (!intervals || !intervals.length) return []
      intervals.sort((a, b) => a[0] - b[0])
      const newDate = [intervals[0]]
      for (let i = 1; i < intervals.length; i++) {
        if (newDate[newDate.length - 1][1] >= intervals[i][0]) {
          newDate[newDate.length - 1][1] = Math.max(newDate[newDate.length - 1][1], intervals[i][1])
        } else {
          newDate.push(intervals[i])
        }
      }
      return newDate
    },

最后当我们获取到了最后需要的数据后,就需要去进行高亮代码展示了

mounted
    const highlightedText = this.highlighted(mergeIndices, needMatch) // 这是一段<code>测试</code>文字,需要<code>通过</code>关键词匹配,<code>已测试中</code><code>通过</code>等等等等
methods
    highlighted(mergeIndices, needMatch) {
      let highlightedText = '' // 初始化高亮后的文本为空字符串
      let startIndex = 0 // 记录每一次高亮结束的位置,需要在下一次高亮的时候从这里开始

      mergeIndices.forEach(([start, end]) => {
        // console.log(startIndex, start, text.substring(startIndex, start))
        highlightedText += needMatch.substring(startIndex, start) // 将高亮前的部分添加到高亮后的文本中
        highlightedText += `<code>${needMatch.substring(start, end + 1)}</code>` // 将高亮的部分添加到高亮后的文本中
        startIndex = end + 1 // 更新下一次高亮的起始位置
      })

      highlightedText += needMatch.substring(startIndex) // 将高亮后的文本的剩余部分添加到高亮后的文本中

      return highlightedText
    },

以上就是全过程了,希望对你有所帮助。
end