如何实现单词相等校验?排查脏话检测机器人功能失效问题
脏话检测功能失效的核心问题与修复方案
现有代码的失效原因
- 严格全等匹配的适配性缺陷:当前代码直接对原始消息内容按空格切分后做
===严格匹配,没有处理大小写、附带标点的干扰。比如用户发送Shit!、Fuck,这类带标点的内容,切分后得到的字符串和词库里全小写、无标点的词汇永远无法匹配,自然不会触发后续删除警告逻辑。 - 状态变量的设计漏洞:用来标记命中状态的
badWord变量是全局定义、没有在每次消息检测时重置初始值的,不仅会出现状态残留的问题(比如之前的消息命中过脏话,后续所有消息都会被误触发删除),也会导致单次检测的状态判断逻辑混乱。 - 异步操作时序问题:
message.delete()、频道发消息、给用户发私信这些都是异步方法,原代码没有加await等待执行完成,容易出现逻辑时序错乱的问题。
修正后的可运行代码
// 违规词库定义 const badWords = ["fuck","hell","shit","bitch","asshole","bastard"] // 消息检测核心逻辑 async function handleMessageDetection(message) { // 每次检测前重置命中标记,避免状态残留 let hasMatchedBadWord = false; // 清洗消息内容:转小写、移除所有非字母和空格的干扰字符 const cleanedContent = message.content.toLowerCase().replace(/[^a-z\s]/g, ""); // 按连续空白切分,过滤掉空字符串 const messageWords = cleanedContent.split(/\s+/).filter(word => word !== ""); // 遍历匹配 for (let i = 0; i < messageWords.length; i++) { for (let u = 0; u < badWords.length; u++) { if (messageWords[i] === badWords[u]) { hasMatchedBadWord = true; break; } } // 命中后直接跳出外层循环,减少无意义的遍历 if (hasMatchedBadWord) break; } // 命中后执行处置逻辑 if (hasMatchedBadWord) { console.log("Deleting message"); await message.delete(); await message.channel.send(`${message.author} 已被警告,违规原因:使用脏话`); await message.author.send(`你在DoGame服务器收到警告,违规原因:使用脏话`); } }
匹配效果优化建议
- 可以用预编译正则的方式替代双重循环,匹配效率更高,还能自动识别独立单词,避免把嵌在正常单词里的脏话片段误判:比如写为
const badWordMatcher = new RegExp(\b(${badWords.join("|")})\b, "i"),直接用badWordMatcher.test(message.content)就能完成全量匹配,不需要手动切分字符串。 - 针对用户刻意绕开检测的写法,可以增加一层简单的字符映射规则,比如把内容里的
@替换为a、$替换为s、0替换为o之后再做匹配,能覆盖大部分常见的变形脏话。
内容的提问来源于stack exchange,提问作者HamzahF
相关产品推荐
相关产品推荐

