JavaScript 如何实现重叠匹配的字符串高亮显示功能
问题描述
假设我们有如下字符串:
"The quick brown fox jumps over the lazy dog"
如果在该字符串中搜索关键词 "ove ver",预期结果是单词 "over" 被高亮标记。
现有实现代码如下:
'The quick brown fox jumps over the lazy dog' .replace(/ove|ver/g, s => s.replace(/\w/g, '<mark>$&</mark>'))
补充说明:搜索单字符 "o" 时不需要高亮到下一个单词边界,预期输出结果为:"The quick br<mark>o</mark>wn f<mark>o</mark>x jumps <mark>o</mark>ver the lazy d<mark>o</mark>g"
解决方案
核心问题是普通全局正则匹配无法处理重叠的匹配项(比如over中的ove和ver存在字符重叠,第一个匹配会吃掉重叠字符导致第二个匹配失败),可以通过先标记所有需要高亮的字符位置,再统一插入标签的方式实现:
function highlightKeyword(str, keyword) { // 转义正则特殊字符,避免注入风险 const escapeRegExp = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // 按空格拆分关键词为多个子匹配模式 const patterns = keyword.trim().split(/\s+/).map(escapeRegExp) if (patterns.length === 0) return str // 构造支持重叠匹配的正向零宽断言正则 const regex = new RegExp(`(?=(${patterns.join('|')}))`, 'g') // 初始化高亮位置标记数组 const highlightFlags = new Array(str.length).fill(false) let match while ((match = regex.exec(str)) !== null) { const matchLen = match[1].length const startIndex = match.index // 标记所有匹配到的字符位置 for (let i = startIndex; i < startIndex + matchLen; i++) { highlightFlags[i] = true } // 避免零宽匹配导致的死循环 if (match[0] === '') regex.lastIndex++ } // 遍历字符串拼接高亮标签 let result = '' let inHighlight = false for (let i = 0; i < str.length; i++) { if (highlightFlags[i] && !inHighlight) { result += '<mark>' inHighlight = true } else if (!highlightFlags[i] && inHighlight) { result += '</mark>' inHighlight = false } result += str[i] } // 处理末尾仍处于高亮状态的边界情况 if (inHighlight) result += '</mark>' return result } // 测试用例 const testStr = 'The quick brown fox jumps over the lazy dog' // 测试多关键词重叠匹配 console.log(highlightKeyword(testStr, 'ove ver')) // 输出:The quick brown fox jumps <mark>over</mark> the lazy dog // 测试单字符匹配 console.log(highlightKeyword(testStr, 'o')) // 输出:The quick br<mark>o</mark>wn f<mark>o</mark>x jumps <mark>o</mark>ver the lazy d<mark>o</mark>g
内容的提问来源于stack exchange,提问作者Niekes
相关产品推荐
相关产品推荐

