Discord.js 实现从带固定前缀的自然语句中提取命令的问题
问题根源
你当前的命令匹配逻辑是切除固定前缀后,取拆分出的第一个单词作为命令名,所以类似Hey Bot show me the ping的句式,切除前缀后第一个单词是show,根本匹配不到ping命令,你的run函数自然不会触发,和你在run内加的判断没有关系。
修复步骤
第一步:调整消息匹配逻辑
把原来的取首个单词匹配命令,改成「切除前缀后的所有内容,遍历全部已注册命令,检查是否包含命令名/别名」即可。为了避免误匹配,建议用正则匹配独立单词,排除命令名作为其他单词一部分的情况。
第二步:替换你的messageCreate事件代码
修改后的完整代码如下:
const client = require(".."); var config = require("../settings/config.json"); var ee = require("../settings/embed.json"); const { MessageEmbed } = require("discord.js"); client.on('messageCreate', async message => { let prefix = config.prefix if (!message.guild) return; if (message.author.bot) return; if (message.channel.partial) await message.channel.fetch(); if (message.partial) await message.fetch(); // 先判断消息是否带前缀,避免无意义处理 if (!message.content.toLowerCase().startsWith(prefix.toLowerCase())) { // 这里保留你原来的@机器人逻辑 if (message.mentions.has(client.user)) { message.channel.send({ embeds: [new MessageEmbed() .setColor(ee.embed_color) .setAuthor(`TEST`) .setDescription(`Use \`${prefix}help\``) .setFooter(ee.embed_footertext, ee.embed_footericon) ] }); } return; } // 切除前缀,拿到后续所有内容 const contentWithoutPrefix = message.content.slice(prefix.length).trim().toLowerCase(); const args = contentWithoutPrefix.split(/ +/); // 遍历所有已注册命令,匹配是否包含命令名/别名(独立单词匹配) let command = null; for (const cmd of client.commands.values()) { // 匹配命令名 const nameRegex = new RegExp(`\\b${cmd.name.toLowerCase()}\\b`); if (nameRegex.test(contentWithoutPrefix)) { command = cmd; break; } // 匹配别名 if (cmd.aliases && cmd.aliases.length > 0) { for (const alias of cmd.aliases) { const aliasRegex = new RegExp(`\\b${alias.toLowerCase()}\\b`); if (aliasRegex.test(contentWithoutPrefix)) { command = cmd; break; } } if (command) break; } } if (command) { if (!message.member.permissions.has(command.permissions || [])) { return message.reply({ embeds: [ new MessageEmbed() .setColor(ee.embed_color) .setDescription(`** 缺少权限:${command.permissions} **`) ] }) } command.run(client, message, args, prefix) } })
第三步:还原你的ping.js代码
你之前修改的run函数逻辑可以删掉,用最初的版本即可,现在只要前缀后的内容包含ping的独立单词,就能触发ping命令的run函数。
可选优化
如果想要匹配更灵活,可以给每个命令新增keywords配置项,比如ping命令可以加:
module.exports = { name: "ping", aliases: ['p'], keywords: ['ping', '延迟', '网速'], // 新增关键词 permissions : ["SEND_MESSAGES"], // 其余代码不变 }
然后在上面的匹配逻辑里,增加对keywords的遍历匹配即可,后续就算用户发Hey Bot 看看网速也能触发ping命令。
内容的提问来源于stack exchange,提问作者Hunwol
相关产品推荐
相关产品推荐

