javascript - 搜索 Discord 消息以设置过滤器
问题描述
我正在尝试在 Discord 消息中搜索匹配的短语,然后使用该短语为过滤后的数组设置过滤器 - 当我只有一个短语要搜索时它可以工作,但它不适用于多个短语或没有输入了短语(如果没有匹配的短语,我希望它没有过滤器) - 感谢所有帮助!
module.exports = {
name: 'mission',
description: 'Randomly selects a mission',
execute(message, args) {
let missionArray = [
{
name: "Incisive Attack",
size: "Combat Patrol",
type: "Eternal War",
source: "BRB",
page: "286"
},
{
name: "Outriders Attack",
size: "Combat Patrol",
type: "Eternal War",
source: "BRB",
page: "287"
},
//more missions here
];
if (message.content.match('Combat Patrol')) {
let filter = {size:"Combat Patrol"};
} else if (message.content.match('Incursion')) {
let filter = {size:"Incursion"};
} else if (message.content.match('Strike Force')) {
let filter = {size:"Strike Force"}
} else if (message.content.match('Onslaught')) {
let filter = {size:"Onslaught"};
let filteredMission = missionArray.filter(function(item) {
for (var key in filter) {
if (item[key] === undefined || item[key] != filter[key])
return false;
}
return true;
});
let mission = filteredMission[Math.floor(Math.random() * filteredMission.length)];
return message.reply(`I have consulted the mission8Ball and you will play:\n**${mission.name}**\nMission Type: ${mission.type}\nBattle Size: ${mission.size}\nSource: ${mission.source}\nPage: ${mission.page}`);
}
}
};
我还想为源和类型设置过滤器。
提前致谢!
解决方案
好的,我基本上重写了你的命令并且有点过火了,但我相信它会让你更容易管理和添加新任务。
解释将在代码的注释中。如果您有意见,我会尽力回答。需要注意的主要事情是,如果值在创建的可能选项中,过滤器只会组装要过滤的数据option_values
。如果有人想按一个不存在的特征进行过滤,它不会被添加到过滤器中,因此过滤size = "AAAAAAAAAAAAA"
与根本不按大小过滤是一样的。
let missionArray = [
{
name: "Incisive Attack",
size: "Combat Patrol",
type: "Eternal War",
source: "BRB",
page: "286"
},
{
name: "Outriders Attack",
size: "Combat Patrol",
type: "Eternal War",
source: "BRB",
page: "287"
},
{ //sorry made my own for testing
name: "Test",
size: "Incursion",
type: "Short war",
source: "BRB",
page: "300"
},
{
name: "Test2",
size: "Incursion",
type: "other type",
source: "BRB",
page: "301"
}
];
let options = [ //what our users can enter in a message to set their filters
"size:", "type:", "source:"
];
//I could've crunched these two into one dictionary but I feel like this way is easier to read and understand
let option_values = { //all the possible values for our filters they can set (ALL LOWERCASE!!!)
size: [
"combat Patrol", "incursion", "strike force", "onslaught"
],
source: [
"brb"
],
type: [
"eternal war", "other type"
], //continue on...
};
//enter array of filtered missions, get one random out
let chooseMission = function (missions) { //courtesy of user rafaelcastrocouto
let mission = missions[Math.floor(Math.random() * missions.length)];
return mission;
}
const regex = new RegExp('"[^"]+"|[\\S]+', 'g'); //We need to parse arguments for filters that might contain multiple words, like "Eternal War". You don't need to understand this exactly. I got it from here https://stackoverflow.com/questions/50671649/capture-strings-in-quotes-as-single-command-argument
module.exports = {
name: 'mission',
description: 'Randomly selects a mission',
execute(message, args) {
//this snippet parses our arguments to allow multi words like 'Eternal War'.
args = [];
message.content.match(regex).forEach(arg => {
if (!arg) return;
args.push(arg.replace(/"/g, ''));
});
let filter = {} //create a dictionary of information we'll filter by later
for (let i = 0; i < args.length; i++) { //loop over each argument
let cmd = args[i]; //This entire block will define that the message !mission size: "Combat Patrol" type: "Eternal War"
//will be parsed as cmd = "size:", param = "Combat Patrol" in one loop then cmd = "type:", param = "Eternal War" in the next
if (options.includes(cmd)) { //if our argument is one of our predefined options ("size:", "type:")
let param = args[i+1];
let key = cmd.slice(0, -1).toLowerCase(); //cut off the last character of our cmd (":"), make it lower for safety
if (option_values[key].includes(param.toLowerCase())) { //if the parameter we gave ("Incursion", etc) is an option we can use for our filter (size, etc)
filter[key] = param; //use key as the key in our filter dictionary to match size to size.
} else {
message.reply(`Unknown parameter for ${key}: ${param}`)
}
}
}
let filtered = missionArray.filter(item => { //item is a mission that contains properties like size, type...
for (let key in filter) { //our keys are already lowercase, try to keep them that way
if (item[key] === undefined || item[key].toLowerCase() != filter[key].toLowerCase())
return false;
}
return true;
});
if (filtered.length == 0) { //if nothing passed the filter (note: this only counts if someone passed a valid option. If someone passes gibberish like "anafbia" for size, the filter wont try and search for matching sizes.
filtered = missionArray; //select our pool of "filtered" missions to be the entire array
message.reply("Can't find a mission matching your parameters.");
}
let mission = chooseMission(filtered);
message.reply(`I have consulted the mission8Ball and you will play:\n**${mission.name}**\nMission Type: ${mission.type}\nBattle Size: ${mission.size}\nSource: ${mission.source}\nPage: ${mission.page}`);
}
};
这是我测试命令的结果:
//set: these inputs should come back with missions
input:
!mission type: "other type" size: "incursion"
output:
@Allister, I have consulted the mission8Ball and you will play:
Test2
Mission Type: other type
Battle Size: Incursion
Source: BRB
Page: 301
input:
!mission type size: incursion type: "other type"
output:
@Allister, I have consulted the mission8Ball and you will play:
Test2
Mission Type: other type
Battle Size: Incursion
Source: BRB
Page: 301
//set: this input should only filter by eternal war due to malformed parameters
input:
!mission type size: wrong thing type: "eternal war"
output:
@Allister, Unknown parameter for size: wrong
@Allister, I have consulted the mission8Ball and you will play:
Incisive Attack
Mission Type: Eternal War
Battle Size: Combat Patrol
Source: BRB
Page: 286
//set: this input provides a correct parameter but there are no missions that match it, so it returns random
input:
!mission size: "Strike Force"
output:
@Allister, Can't find a mission matching your parameters.
@Allister, I have consulted the mission8Ball and you will play:
Incisive Attack
Mission Type: Eternal War
Battle Size: Combat Patrol
Source: BRB
Page: 286
and of course, !mission alone will just return a random mission as well.
推荐阅读
- python - VScode 中导入 sql.connector 中的 ModuleNotFoundError
- javascript - TypeScript - 如果扩展其他东西,类泛型类型太窄,如果不扩展任何东西,则不是
- python - 如何在 django admin 中更改外键字段的大小?
- java - Java Scanner nextInt() 让我按两次 Enter 以使该值被接受
- typescript - Typescript 项目引用:处理引用项目的第三方依赖项
- python - python - 如何使用正则表达式替换字符串中的特定组?
- sql - 如何使用 windows 功能检索第一个日期和最后一个日期?
- kivy - KivyMD navdrawer 是透明的
- php - 获取 JSON React to PHP
- typescript - 在 if else 语句中发出