我正在尝试在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}`);
}
}
};
我还想为来源和类型设置过滤器。
谢谢!
答案 0 :(得分:1)
好吧,我基本上已经重写了您的命令,但有些过分了,但是我相信它将使您更轻松地管理和添加新任务。
说明将包含在代码的注释中。如果您有意见,我会尽力回答。需要注意的主要事情是,过滤器仅在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.
答案 1 :(得分:0)
这是使用简单的for循环解决您的问题的一种方法。 我还将随机选择移到一个函数(chooseMission)中,以避免在“无内容”情况下重复代码。
module = {};
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"
},
{
name: "Incursion Attack",
size: "Incursion",
type: "Eternal War",
source: "BRB",
page: "287"
}
];
let filters = [
'Combat Patrol',
'Incursion',
'Strike Force',
'Onslaught'
];
let chooseMission = function (missions) {
let mission = missions[Math.floor(Math.random() * missions.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}`);
}
for (let f=0; f<filters.length; f++) {
let filterStr = filters[f];
if (!message.content) {
return chooseMission(missionArray);
} else if (message.content.match(filterStr)) {
let filter = {
size: filterStr
};
let filteredMission = missionArray.filter(function(item) {
for (var key in filter) {
if (item[key] === undefined || item[key] != filter[key])
return false;
}
return true;
});
return chooseMission(filteredMission);
}
}
}
};
module.exports.execute({
content: '',
reply: function (mission) {
console.log(mission);
}
});