首页 > 解决方案 > 搜索 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}`); 
            }
}
};

我还想为源和类型设置过滤器。

提前致谢!

标签: javascriptdiscorddiscord.js

解决方案


好的,我基本上重写了你的命令并且有点过火了,但我相信它会让你更容易管理和添加新任务。

解释将在代码的注释中。如果您有意见,我会尽力回答。需要注意的主要事情是,如果值在创建的可能选项中,过滤器只会组装要过滤的数据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.

推荐阅读