前端模糊搜索

前端模糊搜索实现。

转义关键字

避免带有()*等特殊字符的字符串与正则冲突:

1
2
3
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

根据关键字生成匹配正则

将关键字拆分成正则,普通 => /(.*?)(普)(.*?)(通)(.*?)/i

1
2
3
4
5
6
7
8
9
10
11
12
13
function keywordReg(keyword) {
let src = ["(.*?)"];
const ks = keyword.split("");

if (ks.length) {
ks.forEach((s) => {
src.push(`(${escapeRegExp(s)})(.*?)`);
});
}

src = src.join("");
return new RegExp(src, "i");
}

找到最大匹配长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function findMaxMatch(str, keyword) {
const escapeKeyword = escapeRegExp(keyword)
let max = 0
str.replace(escapeKeyword, (s) => {
// 完全匹配,最大
if (keyword === s) {
max = Number.MAX_SAFE_INTEGER
} else if (s.length > max) {
// 最小匹配长度
max = s.length
}
})
return max
}

模糊查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function fuzzySearch(strs, keyword) {
if(Array.isArray(strs) && typeof keyword === 'string' && keyword.trim()) {
// 过滤前后空格
keyword = keyword.trim()
// 根据关键字生成匹配正则
const kr = keywordReg(keyword)
// 存放匹配结果
let result = []
strs.forEach((s) => {
if(typeof s === 'string')
if (kr.test(s)) {
result.push(s)
}
})

// 对匹配结果降序排序,匹配度高的在前
if(result.length) {
result = result.sort((a, b) => findMaxMatch(b, keyword) - findMaxMatch(a, keyword))
}
return result
}
return []
}

demo

1
2
3
4
5
const strs = ["VIP1(默认)", "vip2", "vi普通用户", "会员用户"];
const keyword = " VIP ";
const resultStrs = fuzzySearch(strs, keyword);

// ["VIP1(默认)", "vip2"]

See the Pen 前端模糊查询 by ly023 (@ly023) on CodePen.

参考

https://developpaper.com/fuzzy-search-on-the-front-end/