3

The problem: 50 different commands which are typed into a command line for a program, lets say for telling a robot what to do. Some of the commands have user determined values such as travel north 5 (5 units of predetermined kind). Others are simple commands, scan area, that have no user determined input.

In my courses, I have simply made a chain of

if(userInput == "command"){do something}
else if(userInput == "anotherCommand"){do something else}
else if else if else if

until all of the conditions where met, which have always been few. For the commands I'm working on now, I'm just parsing out the first word to use in the conditional and then using the other words if needed.

I've tried looking for information about this topic, but I keep getting information about how to read in user input and not about the best way of sorting through a large amount of possible user inputs.

Is it just the nature of reading in user input that the only solution is just to have a chain of if else statements until all inputs are covered?

  • If you are just concerned about the performance of doing too many conditional statements based on string comparison, you can consider tokenization (string splitting) followed by string hashing (hash-based comparison). But it will not be easy to reduce the amount of code. – rwong Aug 18 '16 at 4:26
  • 1
    Possible duplicate of Building a string parser for user command and control? – gnat Aug 18 '16 at 6:16
  • see also: Elegant ways to handle if(if else) else – gnat Aug 18 '16 at 6:16
  • @ gnat I didn't know that a "string parser" was a solution to my problem, so even if the answers are similar, I don't believe that they are duplicates. I'm more focused in learning about the ways of solving this problem and less focused on one specified implementation. I'll take any suggestions on how to rephrase the questions so that my meaning is more clear. – WP0987 Aug 18 '16 at 15:50
2

What you are describing is a perfectly reasonable, though ad-hoc way of parsing the commands.

As an alternative you could define a grammar, and formally parse the input.

And there are in-between's as well.

For example, you can set up a simple state machine to process the first word of the command character by character to determine the action to take. Such a state machine would accommodate searching for all (initial command) words at the same time.

For example, let's say you're looking for "travel" or "turn". You set up a state machine where in state 0, "t" leads to state 1, and all others lead to, say, state -1 (error). From state 1, 'r' leads to state 2, and 'u' leads to state 3. From state 2, the rest of 'avel' followed by a separator is accepted, character by character and state by state, as command "travel", and from state 3, the rest of 'urn' followed by a separator is accepted as command "turn" (and everything else results in error).

Such a state machine would avoid the repetitive string comparisons and the extended if-then-elseif-elseif-elseif sequence, which together make the performance way better for words earlier in the sequence, and way worse for words later in the sequence.

  • If you are going to make a state machine for this, you might as well use a parser generator to write it for you and get all of its other benefits with it. – whatsisname Aug 18 '16 at 5:29
2

There are probably better ways to handle this than using a huge if-else block (such as abstracting commands and argument parsing into one or more classes), but essentially you'd be doing the same kind of thing: figuring out the command based on the first token and invoking the associated "action" to parse the rest of the input for the desired arguments, converting them to their desired types, and writing the logic to actually effect those changes.

Alternatively, if you have control over the input format and depending on the language, you could just write the input "commands" in an actual programming language and feed it to an interpreter. For example, if you're writing in JS, you could do something like:

var robot = Robot();
var travel = function(dir, units) {
    robot.move(...);
    // ...
};

//...

var cmd = "travel('north', 5)";
eval(cmd);

This is probably overkill and more work than doing all that manual parsing, since you'd have to figure out how to expose the code that actually does the work (in the example above, the travel function) to whatever scripting language you decide to use (the language that the interpreter parses) and to properly load that context into the interpreter. There are some languages that make this easier than others, because they have a built-in eval() method (or similar) that can run arbitrary pieces of code in the same language and with the existing context that the eval method is in (i.e. whatever is in scope will be defined).

Python is another language that can do this.

1

There are libraries that can help you with this sort of thing, but it's not terribly difficult to create your own abstractions. A common pattern is something like:

registerCommand("travel (north|south|east|west) (\d+)", travelCommand)
registerCommand("scan area", scanAreaCommand)

def travelCommand(args: Array[String]) = ???
def scanAreaCommand(args: Array[String]) = ???

Then you just have to loop through the registered commands until you find one that matches the regex, extract the matches, and pass them to the registered callback.

You can get more sophisticated and build a grammar and parse tree from the registered commands to do things like tab completion and type validation, which some of those aforementioned libraries do, but looping through the regexes is sufficient for a lot of projects.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.