Reputation: 23
I'm programming a poll feature for my bot where I can create a poll by chatting with the bot. The "poll" the bot creates is just a basic message where other users can react to vote. I'm struggling with finding a way to tell the bot which emoji I want for each possible answer. My idea right now is to write the bot a single message for each possible answer which contains an emoji and the answer (":white_check_mark: Yes"). In hours of trying and searching I have not found any way to check whether the first part of the message is an emoji. I found many posts about searching for the pattern of ":", "<:" or "<a:", which every emoji is supposed to start with, but I've tried everything I could come up with and it's not working cause for some reason the emojis are not written in that way. I would appreciate it if anyone could help me with the problem because as of now I have no clue how to continue with my original idea.
Edit: What I basically just need is a way to check whether a message contains an emoji. However, I was asked to attach my code which would be pretty much to give you an idea of how I'm working. I need to check if a message starts with an emoji because it has to so that the bot knows which emoji he needs to react to the message with and he obviously can't react with something that isn't an emoji.
Thanks Noah
Upvotes: 2
Views: 3604
Reputation: 4520
There is actually a much simpler way of checking if a message contains emoji(s), and separating them from message content. (This is posted more for future viewers of this question, as opposed to the OP who has already solved their problem).
Though the accepted answer works for detecting unicode emotes, it uses an external package, is based on an outdated way of doing this from pre-ES6, and overcomplicates things in some ways. You can check if a string contains an emoji, whether unicode or custom discord format (including animated emotes), with a very simple regex. All on a single, succinct line of code.
const emotes = (str) => str.match(/<a?:.+?:\d{18}>|\p{Extended_Pictographic}/gu);
// TESTS:
console.log(emotes("No emotes here"))
// -> null
console.log(emotes("None here 1234 either"))
// -> null
console.log(emotes("One over here 👃"))
// -> ["👃"]
console.log(emotes("One over here also <:yea:123456789012345678>"))
// -> ["<:yea:123456789012345678>"]
console.log(emotes("Two over <a:yea:123456789012345678> here 👃"))
// -> ["<a:yea:123456789012345678>", "👃"]
console.log(emotes("Three 💯 emotes 💯 here 💯"))
// -> ["💯", "💯", "💯"]
This is how this emotes()
method could be used in generic djs code:
if (emotes(message.content)) {
// Do what you want with the emotes
message.reply(`The emotes found were: ${emotes(message.content).join(", ")}`);
}
I will also explain what the regex is doing here so it is understandable. The regex looks for two different scenarios: discord's custom emote format and unicode emotes.
Custom emotes look something like this: <:emotename:123456789012345678>
. They have the emoji's name between two colons, and the ID of the emoji after the last colon. Animated emotes follow the same format, except for an 'a'
added before the first colon: <a:emotename:123456789012345678>
. The first part of the regex (<a?:.+?:\d{18}>
) checks for these two discord custom emote cases. a?
matches 0 or 1 of 'a'
, meaning it will find both animated and unanimated emotes. .+?
matches any combination of characters, in between the two specified colons (representing the emote's name). \d{18}
matches exactly 18 numerical digits (representing the emote's ID).
Unicode emotes represent text emojis and discord's built-in emojis, and they look something like this: 👃
. This was what the OP found challenging to detect in message content. But thanks to ES6, it is possible to match specific categories of unicode characters using regex (assuming you have the u
unicode flag added to your regex, in our case we have that and the g
global flag added). The second part of the regex (\p{Extended_Pictographic}
) matches this case. This matches any unicode character belonging to the category Extended_Pictographic
, or in other words all of the emote characters.
(Note: there actually is a Emote
category that can be used with \p{Emote}
, but this unfortunately matches plaintext numbers and some punctuation on top of all emotes. Extended_Pictographic
matches just the emotes.)
These two parts of the regex are combined with a |
, meaning anything that matches the first OR second regex will be returned in the results. So emotes()
will return an array of any unicode or custom discord emotes found in the provided string, or null
if none are found.
Upvotes: 4
Reputation: 9310
I recommend doing something like the following: First I am going to create the basic message handling for your command. Check out the discord.js guide if you haven't done it yet.
client.on("message", (message) => {
if (!message.content.startsWith("!poll")) return;
});
Notice that I didn't worry about things like bot messages or DMs for simplicity reasons above.
Now concerning the emoji identification. discord.js or Discord, in general, does actually give you the emojis in Unicode format and NOT marked between two colons like in the Discord User App. This means you have to split up the message.content
differently. The way I'm doing it in the snippet below might not work for animated emojis. Unfortunately, I can't test that because I don't have Discord Nitro. However, you can just extend the match
If-condition yourself. This related question is very useful for what you are trying to do.
As I experienced myself it becomes quite difficult to write a RegEx that matches ALL thousands of emojis out there. Therefore I suggest using an NPM-package called emoji-regex
Notice I created a sample message object so you can see what we are working with.
npm i emoji-regex
const emojiRegex = require('emoji-regex/RGI_Emoji.js');
const message = {
content: "!poll 👍 👎",
};
const re = emojiRegex();
let match;
let emojis = [];
while ((match = re.exec(message.content)) != null) {
emojis.push(match[0]);
}
console.log(emojis);
Finally let's put it all together:
const Discord = require("discord.js");
const client = new Discord.Client();
const emojiRegex = require("emoji-regex/RGI_Emoji.js");
client.on("message", async (message) => {
if (!message.content.startsWith("!poll")) return;
console.log(message.content);
const re = emojiRegex();
let match;
let emojis = [];
while ((match = re.exec(message.content)) != null) {
emojis.push(match[0]);
}
const sent = await message.channel.send("This is my poll!");
emojis.forEach(async (e) => {
await sent.react(e);
});
});
client.login("your-awesome-token-goes-here-:D");
Don't forget to make your client.on("message", async () => ...
-callback and the .forEach(...
-callback async because I'm using Asynchronous JavaScript in the sample above.
Now if you want to create your Reaction Collector I recommend - once again - follow the discord.js Collectors guide.
Upvotes: 1