I'd be tempted to write this as a lexer-parser pair, like a script interpreter / compiler front-end.
The lexer reads the string, cuts out the next "token" to handle, skipping over whitespace or irrelevant punctuation, and standardizing the vocabulary of tokens (say, flattening to lowercase or merging synonyms/spelling variants/permitted typos).
The parser can then act on a higher level, describing the sequences of tokens it expects/accepts for particular commands.
The style of lexer I've used in the past exposes two ways of processing the next token:
Expect checks to see if the next token matches a particular criterion. If it does, it consumes it and advances to the next token. If it doesn't, it generates an error.
We can use this for transitive verbs like "Take" by expecting an object word to follow, and complaining "Take what?" if this expectation is not met.
Accept checks if the next token matches a criterion. If it does, it consumes it and skips ahead to the next token after it, otherwise it does nothing at all.
This is good for allowing optional words like "Take screwdriver" or "Take the screwdriver" without a big combinatoric explosion of if/else branches for every possible phrasing.
Similar to abathur's answer, I'd recommend storing a list of command tokens paired with a function pointer / delegate representing the action it performs. Then you can search your array of commands for a match for the first token, and fire off the appropriate logic. If you pass the lexer down into that command, it can use it to recursively check the subsequent tokens as needed.
So we might have something like this:
CommandResult TakeCommand(Scene scene, Lexer Lexer) {
// Optional A / An / The / That / This
lexer.Accept(Token.Articles);
// You can extend this to handle things like
// "Take one of / take two / take all"
// if(lexer.Accept(Token.Quantifier)) ...
// Or specific flavours of item...
// "Take the big blue screwdriver"
// while(lexer.Accept(Token.Descriptor))...
// Check that they provided an object to take.
if(lexer.Expect(Token.Identifiers) == false)
return CommandResult.Error("Take what?")
// Validate that the named thing is an inventory item.
var item = GetInventoryItemFromToken(lexer.consumedToken);
if(item == null)
return CommandResult.Error("You can't take that.");
// Validate that there is such a thing in this scene/context.
if(scene.ContainsItem(item) == false)
return CommandResult.Error("There's no {0} here.", item.canonicalName);
// Finally, defer the actual inventory operation to the scene
// (it might want to implement special rules,
// like "you can't just take George's false teeth,
// you'll have to offer something in trade!" or
// "as soon as you lift the idol, the whole temple
// begins to shake..."
return scene.Take(item);
}
Now you can wire up your commands something like...
parser.RegisterCommand(Token.Take, TakeCommand);
Depending on your setup, you may be able to treat these command mappings as data & modular action components, rather than hard-coding them all.