如何修改正则表达式,删除字符串重复单词时排除指定词汇?
解决删除重复单词但保留指定单词的问题
你的原正则表达式其实存在一些问题,比如它会匹配较长的连续字符(可能包含多个单词),而不是单个独立单词,而且没法直接实现"排除指定单词"的需求。下面给你两种解决方案,优先推荐更灵活的JavaScript回调函数方式:
方案一:使用回调函数(推荐,灵活易维护)
这种方式可以动态处理排除列表,还能保留原字符串的标点和空格格式,可读性也更强:
setFinal(final) { // 1. 定义需要排除的单词(这些单词重复也不会被删除,可根据需求修改) const excludedWords = new Set(['the', 'a', 'an', 'and']); const seenNonExcluded = new Set(); // 2. 拆分字符串为「单词」和「分隔符(空格、标点等)」,保留原格式 const words = final.match(/\b[\w'-]+\b/g) || []; // 匹配单词,支持连字符和撇号 const separators = final.match(/[^\w'-]+/g) || []; // 匹配非单词部分 const resultParts = []; let idx = 0; // 3. 遍历合并,处理重复逻辑 while (idx < words.length) { const currentWord = words[idx]; const lowerWord = currentWord.toLowerCase(); // 不区分大小写去重(不需要的话可删除) if (excludedWords.has(lowerWord)) { // 属于排除列表的单词,直接保留 resultParts.push(currentWord); } else { // 非排除单词,只保留第一次出现的 if (!seenNonExcluded.has(lowerWord)) { resultParts.push(currentWord); seenNonExcluded.add(lowerWord); } } // 添加上对应的分隔符(比如空格、逗号) if (idx < separators.length) { resultParts.push(separators[idx]); } idx++; } // 处理字符串末尾的分隔符(比如以标点结尾的情况) if (separators.length > words.length) { resultParts.push(separators.at(-1)); } // 合并结果并去除首尾空格 const res = resultParts.join('').trim(); // ... 其他代码 return res; }
代码说明:
- 用
Set存储排除单词和已出现的非排除单词,保证查找效率 - 拆分单词和分隔符是为了保留原字符串的格式(比如
"hello, world hello"处理后会变成"hello, world",而不会破坏标点) - 支持不区分大小写去重(如果需要严格区分大小写,删掉
toLowerCase()即可)
方案二:纯正则表达式(适合固定排除列表)
如果你的排除列表是固定不变的,可以用正则的否定前瞻来实现,但这种方式局限性较大(排除列表过长时正则会很臃肿,且无法动态修改):
setFinal(final) { // 把排除单词转成正则的否定前瞻,注意转义特殊字符 const excluded = 'the|a|an|and'; // 正则逻辑:匹配非排除的单词,且后面存在重复的该单词 const regex = new RegExp(`\\b(?!(${excluded})\\b)(\\w+)\\b(?=.*\\b\\2\\b)`, 'gi'); // 替换重复的非排除单词为空,然后去首尾空格 let res = final.replace(regex, '').trim(); // ... 其他代码 return res; }
注意事项:
- 如果排除单词包含正则特殊字符(比如
.、*),需要先转义(可以用word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')处理) - 这种方式只会删除前面的重复项,且可能因字符串中其他内容干扰出现匹配错误,不如方案一可靠
内容的提问来源于stack exchange,提问作者Matteo Pietro Peru




