Próbuję zrobić Bot Discord, który wykonuje pewne interakcje z serwerem.

Napisałem jakiś kod tego rodzaju działa, ale jest z nim duży problem. Oto mój kod:

if (command === "file") {

        var accusor = message.author.id;
        var username = args[0];
        var reason = args[1];
        var punishment = args[2];
        var duration = args[3];
        if(!duration) duration = "N/A";
        console.log("Returning last " + amount + " for " + username);
        request.post({url:'http://grumpycrouton.com/kismet/api/post_complaint.php', form: {accusor:accusor,search:username,reason:reason,punishment:punishment,duration:duration}}, function(err,httpResponse,body) { 
            message.reply(body); 
        });
    }

Polecenie to !file {playername} {reason} {punishment} {duration}, ale problem polega na tym, że czasami kilka zmiennych może mieć wiele słów. Na przykład {reason} może być czymś w rodzaju "gracza miał zły czas", ale mój kod nie jest w stanie przeanalizować tego poprawnie ze względu na sposób, w jaki argumenty są podzielone.

Powiedzmy, że to polecenie zostanie wprowadzone:

!file GrumpyCrouton "Player had a bad time" Kick "1 Day" Ale argumenty będą one rozłożone inaczej, ponieważ 3rd argument ma w nim spacje, ale regex przelicza całe argument przez przestrzenie niezależnie od cytatów. Zasadniczo niezgoda ignoruje cytaty i wykorzystuje każde słowo jako własny argument, dzięki czemu {punishment} i {X2}} ma indeks argumentu, który ma 6 i 7 zamiast 2 i 3, ponieważ każde słowo jest liczone jako argument.

W ten sposób moje argumenty są czytane:

const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();

Jak mogę to zrobić, aby ciągi były dołączone w cytatach, są czytane jako pojedynczy argument zamiast wielu?

1
GrumpyCrouton 4 czerwiec 2018, 01:44

3 odpowiedzi

Można znaleźć wszystkie wskaźniki cudzysłowów i użyć tych informacji, aby prawidłowo podzielić wkład, przekazując go do Input.Substring. Coś takiego powinno działać:

const input = '!file GrumpyCrouton \"Player had a bad time\" Kick \"1 Day\"';
var raw = input;
raw = raw.split(' ');
let command = raw.splice(0, 1)[0]; // splice out the command (splice returns an array)
let user = raw.splice(0, 1)[0];    // splice out the user

let recompose = raw.join('');      // recompose the string WITHOUT any spaces

let indices = []; // find the indices of the quotation marks
for (var i in recompose) {
    let char = recompose[i];
  if (char === '"') {
    indices.push(i);
  }
}

console.log(indices, recompose);
if (indices.length == 4) { // OK!
  // use the indices to break up input string into substrings
  let reason = recompose.substring(indices[0] + 1, indices[1]);
  let punishment = recompose.substring(indices[1], indices[2]).replace('"', '');
  let duration = recompose.substring(indices[2], indices[3]).replace('"', '');
  console.log(command);
  console.log(user);
  console.log(reason);
  console.log(punishment);
  console.log(duration);
} else {
    // bad input!
}

Możesz podać ten kod, spróbuj JSFiddle!

1
bluecereal 5 czerwiec 2018, 03:49

Możesz dodać bardziej wyraźny ogranicznik taki jak "|" i użyj podziału ('|')

Twoje wejście byłyby jak:! Plik Grumpycrouton | "Gracz miał zły czas" | Kopać |. "1 dzień"

0
Matt Pengelly 3 czerwiec 2018, 22:51

Prosty Regex zrobi sztuczkę :)

const input = 'ban user "Look at what you have done!" 7d "This is another string" value';
const regex = new RegExp('"[^"]+"|[\\S]+', 'g');
const arguments = [];
input.match(regex).forEach(element => {
    if (!element) return;
    return arguments.push(element.replace(/"/g, ''));
});
console.log(arguments);

/*
 * Use a function with a spreader like:
 * doSomething(...arguments);
 */
0
Matthew 4 sierpień 2019, 16:04