0

I am coding a discord bot. Discord is a social platform with a chat, and you can code bots there.

In order to trigger bot commands, the bot reads every single message sent to the chat. It's sent to him as a string.

By using this: var args = msg.content.split(' '); the bot separates every single word into an array. Now, I can do this: if (args[0] === '!command') { //code }

My bot will keep track of League of Legends players. I want to be able to put the name and add a reason for the tracking. All of that will go into a database. At first, it seems simple, I can just do this:

if (args[0] === '!command') {
  var player = args[1];
  var reason = args[2];
}

Now, if I send !command player1 reasons the bot will get it right.

The issue is, in League of Legends, having spaces in your nickname is allowed. At the same time, one single word for the reason might fall short. If you tried to do this: !command "player one" reasons the bot wouldn't get player oneas the args[1], instead, "player would be args[1] and one" would be args[2]. At the same time, reasons would now be args[3] instead of args[2].

Is there a simple way to tell javascript to ignore spaces inside quotation marks so it doesn't split the string there?

I could use a different character to split the string, but writing a command like !command-player-reasons there feels weird and a patch instead of an actual solution.

  • Is double qoute`"` allowed in name? I think you can use a tab `\t` to be the separator? i.e. `!command\tplayer one\the is awesome` – chakwok Jun 04 '20 at 03:34
  • https://stackoverflow.com/questions/2817646/javascript-split-string-on-space-or-on-quotes-to-array – saketh Jun 04 '20 at 03:36
  • Does this answer your question? [Count content inside quotes as one argument](https://stackoverflow.com/questions/62104987/count-content-inside-quotes-as-one-argument) – Federico Grandi Jun 04 '20 at 08:05

4 Answers4

0

I'd advise you to parse command and it's arguments separately. It will admit to write more flexible commands. For example:

var command = msg.content.substring(0, msg.content.indexOf(' '));
var command_args_str = msg.content.substring(msg.content.indexOf(' ') + 1);
switch(command) {
    case '!command':
        var player = command_args_str.substring(0, command_args_str.lastIndexOf(' '));
        var reason = command_args_str.substring(command_args_str.lastIndexOf(' ') + 1);
        break;
}
Helgi
  • 111
  • 3
0

It's possible, but probably less complicated for users of the bot to just use a different character to split the two arguments.

E.g. !command player one, reasons if you knew , (or |, =>, etc..) wasn't part of a valid username.

If you only support quotes for the username part, it's easier:

const command = `!command`;
const msg1 = {content: `${command} "player one" reasons ggg`};
const msg2 = {content: `${command} player reasons asdf asdf`};

function parse({content}) {
  if (!content.startsWith(command)) {
    return; // Something else
  }
  content = content.replace(command, '').trim();
  const quotedStuff = content.match(/"(.*?)"/);
  if (quotedStuff) {
    return {player: quotedStuff[1], reason: content.split(`"`).reverse()[0].trim()};
  } else {
    const parts = content.split(' ');
    return {player: parts[0], reason: parts.slice(1).join(' ')};
  }
  console.log(args);
}

[msg1, msg2].forEach(m => console.log(parse(m)));
Chase
  • 3,028
  • 14
  • 15
0

You could use regexp here:

const s = `!command "player one" some reason`;

function getArgsFromMsg1(s) {
  const args = []
  if ((/^!command/).test(s)) {
    args.push(s.match(/"(.*)"/g)[0].replace(/\"/g, ''))
    args.push(s.split(`" `).pop())
    return args
  } else {
    return 'not a command'
  }

}

// more elegant, but may not work
function getArgsFromMsg2(s) {
  const args = []
  if ((/^!command/).test(s)) {
    args.push(...s.match(/(?<=")(.*)(?=")/g))
    args.push(s.split(`" `).pop())
    return args
  } else {
    return 'not a command'
  }
}

console.log(getArgsFromMsg1(s));
console.log(getArgsFromMsg2(s));
muka.gergely
  • 8,063
  • 2
  • 17
  • 34
0

Update:

Because OP doesn't seem very experienced with the language , I've chosen to provide an answer that's easy to read. The proper way to do this would be with using regex capturing groups: https://stackoverflow.com/a/18647776/16805283


This will check if any quotation marks are in `message.content` and change how you grab your args array. If no quotation marks are found, it falls back to your own code for generating the args array. Keep in mind, this will only work if **there's exactly 2** quotation marks across the `message.content`, so no quotation marks should be used in reasons
// Fake message object as an example
const message = {
  content: '!command "Player name with a lot of spaces" reason1 reason2 reason3'
};

const { content } = message; 
let args = [];
if (content.indexOf('"') >= 0) {
  // Command
  args.push(content.slice(0, content.indexOf(' ')));
  // Playername
  args.push(content.slice(content.indexOf('"'), content.lastIndexOf('"') + 1));
  // Reasons
  args.push(content.slice(content.lastIndexOf('"') + 2, content.length));
} else {
  args = content.split(' ');
}
// More code using args

if you want the playerName without the quotation marks:

playerName = args[1].replace(/"/g, '');`