如何在 JavaScript 中基于多个关键词实现模糊搜索过滤
针对多关键词模糊搜索,常见方法包括使用`includes()`实现全局子串匹配,用`\b`正则进行单词边界精准匹配,或用`^`锚点限定首词前缀匹配。需对输入转义防注入,并配合防抖优化性能。上述方法可根据实际场景灵活选用。
本文介绍如何用 Ja vaScript 实现更智能的搜索过滤逻辑,支持对输入的多个词进行子串匹配或单词边界匹配,解决仅匹配开头导致漏检的问题。
先说一个常见的坑:很多人在做搜索建议(比如书名、文章标题的自动补全)时,想当然地用 match 或者 substr 去判断输入内容是不是字符串的开头。结果呢?用户搜“funny stories”,系统却死活匹配不到那条只包含“stories”的条目。问题就出在匹配逻辑太死板——它要求整个输入必须作为前缀出现,而不是去内容里找。
那么,怎么解决这个问题?下面给出几种实际可用的方案,按场景选就行。
✅ 推荐方案一:全局子串匹配(最常用)
最直接的办法,就是使用 String.prototype.includes(),做一次大小写不敏感的“包含”判断。简洁、高效,能覆盖绝大多数需求:
const filteredSuggestions = suggestions
.filter(({ name }) =>
name?.toLowerCase().includes(searchInput.toLowerCase())
);
✅ 优势在哪?
- 输入“funny”→ 能命中“Funny stories”、“Not funny at all”;
- 输入“stories”→ 同样能匹配“funny stories”和“short stories”;
- 加上
name?.toLowerCase()的可选链调用,能有效防范空值导致的运行错误。
⚠️ 不过得留个心眼:这是“宽松匹配”,可能产生一些意料之外的匹配结果。比如搜索“art”会连“part”一起捞出来。如果对精准度有更高要求,请往下看正则方案。
✅ 推荐方案二:单词边界匹配(按词首匹配)
如果你的业务场景要求更精确——比如只匹配“独立单词的开头”,搜索“s”应当命中“Serious stories”中的“Serious”或者“stories”,但绝不能匹配“passion”里的“ss”——那就得请出正则,配合 \b 边界符:
const escapedInput = searchInput.replace(/[.*+?^${}()|\[\]\\]/g, '\\$&');
const regex = new RegExp(`\\b${escapedInput}`, 'i');
const filteredSuggestions = suggestions
.filter(({ name }) => regex.test(name));
来看几个具体的匹配行为:
- 输入“s”→ 匹配“Serious stories”、“funny stories”(因为“stories”以 s 开头);
- 输入“st”→ 匹配“stories”,但不匹配“start”(除非内容里真有这个词);
- ✅ 代码里已经做了正则元字符的转义处理,用户输入“a+b”也不会引发语法报错。
✅ 进阶:首词开头匹配(严格前缀)
如果业务要求“仅匹配标题第一个单词的开头”——比如搜“s”只返回“Serious stories”,不返回“funny stories”——那就用 ^ 锚点来限定:
const regex = new RegExp(`^${escapedInput}`, 'i');
// 注意:name 需要先 trim() 去除开头空格,确保 ^ 锚定准确
const filteredSuggestions = suggestions
.filter(({ name }) => regex.test(name?.trim()));
? 总结与选型建议
| 场景 | 推荐方法 | 特点 |
|---|---|---|
| 快速原型 / 宽松搜索 | includes() | 简单、兼容性好、性能优 |
| 关键词驱动 / “搜词不搜字” | \b 正则 | 精准、符合用户直觉(如搜索“js”不匹配“object”) |
| 品牌/标题前缀搜索(如目录导航) | ^ 正则 | 最严格,适合结构化命名场景 |
最后提醒一句:丢到生产环境之前,务必对 searchInput 做防空和防注入处理(上面已经演示了转义写法)。另外,建议配合防抖(debounce)来优化输入体验,别让每一次按键都触发一次全量过滤。


































