Search code examples
javadiscord-jda

How to work with multiple strings and different types of data on a single command line with Discord JDA?


I want make a Event Manager function for my Discord bot but I have a problem to resolve. The bot uses the split() method to read each string and thus execute a command. However, one day, I ran into a problem of needing to return multiple strings (for example, an event title, which can vary in lenght). I managed to get around using StringBuffer(), but the way I did it's only sufficient if there is no other type of data after this string sequence. The split() method makes it much easier to create commands, because I can work with the indexes, but it is getting in the way when I need to join multiple strings and work with other types of data after.

Currently the command to create an event, in summary, works as follows:

$event title [Str title]
$event url [Str url]
$event slots [int slots]

How I would like it to work:

$event '[Str title]' [Str url] [int slots]

If the title consists of multiple strings, it must have quotation marks at the beginning and end and everything inside is part of it.

This is an example of code I currently use:

public class EventManager extends ListenerAdapter {

private String title;

public void onGuildMessageReceived(GuildMessageReceivedEvent e) {
     
     String[] message = e.getMessage().getContentRaw().split(" ");
     EmbedBuilder eb = new EmbedBuilder();

     if (message[0].equalsIgnoreCase("$event") && message[1].equalsIgnoreCase("title")) {
        
         StringBuffer sb = new StringBuffer();
         for (int i  = 2; i < message.length; i++) {
            sb.append(message[i]);
            sb.append(" ");
         }
            
         this.title = sb.toString();
         
         eb.setColor(Color.GREEN);
         eb.setDescription("Title: " + title);
         e.getChannel().sendMessage(eb.build()).queue();

    }

}

}

Is there an efficient way to do this? That is, on a single command line read different types of data?


Solution

  • One thing you can do is split your message using RegEx. If you construct a regex that matches strings enclosed in quotes, you can use it to split your initial string into an array. With that array you can use indexes to reference to your preferred arguments.

    I use the following code to split my message:

    private ArrayList<String> split(String subjectString){
        ArrayList<String> matchList = new ArrayList<>();
        Pattern regex = Pattern.compile("\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'|[^\\s]+");
        Matcher regexMatcher = regex.matcher(subjectString);
        while (regexMatcher.find()) {
            if (regexMatcher.group(1) != null) {
                // Add double-quoted string without the quotes
                matchList.add(regexMatcher.group(1));
            } else if (regexMatcher.group(2) != null) {
                // Add single-quoted string without the quotes
                matchList.add(regexMatcher.group(2));
            } else {
                // Add unquoted word
                matchList.add(regexMatcher.group());
            }
        }
        return matchList;
    }
    

    So if you pass $event 'Some title' a_url 2 to that method you will receive an ArrayList: ["$event", "Some title", "a_url", "2"]. Then you just have to parse the integers when needed.

    Note that the quotes from the initial message aren't included in the array

    I found this regex on another SO, will add a reference to it when I find it again.