如何在文本字符串中查找重复二元、三元关键词组以实现关键词密度统计功能
连续多词词组重复检测实现方案
核心实现逻辑
1. 文本预处理
先对输入的原始字符串做标准化处理,降低后续匹配的噪声:
- 过滤掉标点、特殊符号,仅保留单词字符和空格
- 合并多个连续空格为单个空格,去除字符串首尾空白
- 按空格拆分得到有序的单词数组
如果需要大小写不敏感的统计,可在这一步将所有单词统一转为小写。
2. 通用n元词组生成
写可复用的n元词组生成方法,适配二元、三元甚至更长的词组检测需求:
/** * 生成n元词组数组 * @param {Array} words 预处理后的单词数组 * @param {Number} n 词组长度,2为二元词组,3为三元词组 * @returns {Array} 所有连续n词组成的词组数组 */ function generateNGrams(words, n) { const ngrams = [] // 遍历终止位置为数组长度减n,避免取到超出范围的元素 for (let i = 0; i <= words.length - n; i++) { const currentGram = words.slice(i, i + n).join(' ') ngrams.push(currentGram) } return ngrams }
比如输入单词数组["What", "is", "your", "name", "What", "is", "your", "hobby"],传入n=2时,生成的二元词组数组就会包含["What is", "is your", "your name", "name What", "What is", "is your", "your hobby"]。
3. 词组频率统计
这一步逻辑和你已实现的单个单词统计完全一致,统计生成的n元词组的出现次数,过滤掉仅出现1次的非重复词组即可:
function countRepeatGrams(ngrams) { const countMap = new Map() ngrams.forEach(gram => { countMap.set(gram, (countMap.get(gram) || 0) + 1) }) // 仅返回重复出现的词组,按出现次数倒序排序,方便UI直接渲染 return Array.from(countMap.entries()) .filter(([gram, count]) => count >= 2) .sort((a, b) => b[1] - a[1]) }
4. 整体功能封装
把上述步骤串起来,支持同时统计多种长度的词组:
function getGramStatistics(text, supportGrams = [2, 3]) { // 文本预处理 const cleanedText = text.replace(/[^\w\s]/g, '').replace(/\s+/g, ' ').trim() const words = cleanedText.split(' ') const result = {} supportGrams.forEach(n => { const ngrams = generateNGrams(words, n) result[`${n}元重复词组`] = countRepeatGrams(ngrams) }) return result } // 测试示例 const testStr = "My name is not Kevin this is not fun." console.log(getGramStatistics(testStr, [2])) // 输出:{ "2元重复词组": [["is not", 2]] }
优化提示
- 可根据业务需求增加停用词过滤,过滤掉由无意义助词(比如
的、is、a等)组成的高频无效词组 - 如果需要统计长文本,可采用流式处理避免一次性加载全部内容造成性能问题
- 单词拆分逻辑可根据需要适配中文,改用中文分词库做拆分即可
内容的提问来源于stack exchange,提问作者Cevin Thomas
相关产品推荐
相关产品推荐

