Credit: Michael Robin
You need to use regular expressions to match strings and then automatically call functions with arguments based on the matched strings.
Once again, a class offers a good way to package together some state and some behavior:
import re class Dispatcher: def _dispatch(self, cmdList, str): """ Find a match for str in the cmdList and call the associated method with arguments that are the matching grouped subexpressions from the regex. """ for comment, pattern, command in cmdList: found = pattern.match(str) # or, use .search( ) if found: return command(self, *found.groups( )) def runCommand(self, cmd): self._dispatch(Commands, cmd) # example methods def cmd1(self, num, name): print "The number for %s is %d" % (name, int(num)) return 42 def cmd2(self, partnum): print "Widget serial #: %d" % int(partnum) Commands = [ [ 'Number-to-name correspondence', r'X (?P<num>\d+),(?P<name>.*)$', Dispatcher.cmd1], [ 'Extract Widget part-number', r'Widget (?P<partnum>.*)$', Dispatcher.cmd2], ] # Prepare the Commands list for execution by compiling each re for cmd in Commands: try: cmd[1] = re.compile( cmd[1] ) except: print "Bad pattern for %s: %s" % ( cmd[0], cmd[1] )
In Python, it’s generally best to compile regular
expressions into re
objects. The
re
module does some caching of string-form
regular expressions that you use directly, but it’s
still better to make sure that regular expressions are not needlessly
recompiled. The string form is still available as
r.pattern
for any compiled re
object r
, anyway, should you need it (e.g., for
debugging/logging purposes).
You can use regular expressions to match strings (or search into strings) and automatically call appropriate functions, passing as arguments substrings of the matched string that correspond to the groups of the regular expression.
This recipe exemplifies one approach to this solution. The idea is that:
r = self.runCommand("X 36,Mike")
automatically calls:
cmd1(self, "36", "Mike")
and binds the variable r
to 42
,
the result of cmd1
.
This specific example might be best approached with direct string
manipulation (testing str[0]
, then using the
split
method of strings), but regular expressions
let you handle much more complicated cases with nearly equal ease.
An idiomatic Pythonic approach is to put each pattern to be compiled directly in the structure to be created at load-time. For example:
Cmds = ( (re.compile(r"^pa(t)t1$"), fn), ... )
This is simple, if you don’t require any special processing, but I think it’s a little prettier to avoid including code in data-structure initializers.
Get Python Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.