2

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

  • Consider editing your question to include the applicable code that you had created that is still deficient towards your goal. – JohnH May 23 '21 at 17:55
  • Can you show what you have tried so far? – user15517071 May 23 '21 at 19:28
  • @JohnH I edited my post, I hope my goal became clear, if you still need the code I can provide it but I'm not really sure how I could present it in the best way so that you fully understand the idea behind the code or rather it would take some time to explain it. As I said I basically need a way to identify emojis. Let me know if I provided enough information – staubigerkaktus May 23 '21 at 19:37
  • @user15517071 I've tried multiple things, but basically these to things with variations I think: I've searched the message for ":", "<:" and " – staubigerkaktus May 23 '21 at 19:46
  • This is my first time posting questions regarding programming and I'm still learning so I'm sorry if I left out important information or else but just feel free to just ask, I will try to answer everything I know. I appreciate your help. – staubigerkaktus May 23 '21 at 19:51
  • Emoji's are UTF characters and you could search for them as you would search for any character, [like so](https://stackoverflow.com/a/60930873/145939). However discord's custom server emoji's are handled entirely differently. If however you are looking for different ways to implement a poll, may I suggest you take a look at [my own implementation at github](https://github.com/Ant-V/discordjs-poll-creator) – Ant May 23 '21 at 20:15

2 Answers2

2

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.

Cannicide
  • 4,360
  • 3
  • 22
  • 42
1

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");

Stack Overflow Discord emoji test

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.

Behemoth
  • 5,389
  • 4
  • 16
  • 40
  • Hey, thanks for your answer! Sadly it does not seem to work for me. My code for the testing command looks like this: `try { let re = /\:.*?\:/gi; let match; let emojis = []; while ((match = re.exec(message.content)) != null) { emojis.push(match[0]); } console.log(emojis[0]); } catch (error) { message.channel.send(":octagonal_sign: **Fehler!** Bitte melde diesen Fehler beim Support!"); console.error(error); }` I basically just copied your work for this but when I use the command the emojis [...] – staubigerkaktus May 23 '21 at 22:24
  • [...] are not found. I'll show you what I mean. https://prnt.sc/13bkwz9 https://prnt.sc/13bky10 https://prnt.sc/13bkyz2 (console log) The emojis in my discord message simply don't get recognized. Maybe I got you wrong but I think I did everything the way to described it. – staubigerkaktus May 23 '21 at 22:29
  • Found my mistake. Let me just edit my answer really quick :D – Behemoth May 24 '21 at 09:44
  • I was actually totally wrong about the Unicode-thing. Discord actually give you the emojis in Unicode-format. I could have sworn it was the other way. Well, arrogant I thought I could answer the question without running my code once. – Behemoth May 24 '21 at 10:10
  • Thank you so much! The code works now, appreciate your help. – staubigerkaktus May 24 '21 at 16:59