JS宏里用编辑距离模糊匹配两表
wils
Lv.4 核心创作者
刚看到有朋友问,核对两表时如何模糊匹配名称
https://bbs.wps.cn/topic/93946
过去即使导入了编辑距离库,写JS代码还是挺麻烦的
库用的是fastest-levenshtein
https://www.npmjs.com/package/fastest-levenshtein
现在有了灵犀,正好试试
写个js宏,从Sheet1的UsedRange读取表1,从Sheet2的UsedRange读取表2,两者都去掉表头,然后对表1的每一行执行:将前3列用join(",")合并成一个字符串,用lev.distance()对比这个字符串和表2里每一行的前三列用join同样连接的字符串,找出最匹配的行,然后将匹配的行输出到Sheet1的F列的对应行,有现成的lev.distance方法
后面稍作修改就得到了够用的代码
function CommandButton1_Click() {
const ws1 = Sheets.Item("Sheet1");
// ===== 先清空 F 到 I 列(数据区,从第 2 行起)=====
if (ws1.UsedRange.Rows.Count >= 2) {
const lastRow = ws1.UsedRange.Rows.Count;
ws1.Range(ws1.Cells(2, 6), ws1.Cells(lastRow, 9)).ClearContents();
}
const getData = sheet => sheet.UsedRange.Value2.slice(1); // 去表头
const data1 = getData(ws1);
const data2 = getData(Sheets.Item("Sheet2"));
if (!data1.length || !data2.length) return alert("数据不足");
const keys2 = data2.map(r => r.slice(0, 3).join(",")); // 表2 比较键,只算一次
// 逐行匹配,返回表2 匹配行的整行(合并前)
const results = data1.map(row => {
const key1 = row.slice(0, 3).join(",");
let best = -1, dist = Infinity;
for (let j = 0; j < keys2.length; j++) {
const d = lev.distance(key1, keys2[j]);
if (d < dist) { dist = d; best = j; if (d === 0) break; }
}
return best >= 0 ? data2[best].slice() : [];
});
const cols = results.reduce((m, r) => Math.max(m, r.length), 0); // 最宽列数
results.forEach(r => { while (r.length < cols) r.push(""); }); // 补成矩形
// ===== 写入:从 F 列(第6列)开始,第2行起 =====
ws1.Range(
ws1.Cells(2, 6),
ws1.Cells(results.length + 1, 5 + cols)
).Value2 = results;
alert(`完成,${results.length} 行 × ${cols} 列`);
}通过网盘分享的文件:编辑距离模糊匹配.xlsm
链接: https://pan.baidu.com/s/1c3NHBUVlNxiBK0JrUvOWDg?pwd=r961 提取码: r961
就像帖子里朋友说的,名称虽然稍有不同,但加上规格和单位,就比较准确了
但还是要小心核对,毕竟是模糊匹配,还是可能出错的,一定小心。。。
==================
发现代码需要修改,d应该再除以两个字符串的总长
Lv.3 优质创作者
Lv.3 优质创作者
Lv.4 核心创作者