best way to do a series of regexp checks with groups

Jonathan Fine jfine at pytex.org
Mon Jan 24 16:11:14 EST 2005


Mark Fanty wrote:
> In perl, I might do (made up example just to illustrate the point):
> 
> if(/add (\d+) (\d+)/) {
>   do_add($1, $2);
> } elsif (/mult (\d+) (\d+)/) {
>   do_mult($1,$2);
> } elsif(/help (\w+)/) {
>   show_help($1);
> }
> 
> or even
> 
> do_add($1,$2) if /add (\d+) (\d+)/;
> do_mult($1,$2) if /mult (\d+) (\d+)/;
> show_help($1) if /help (\w+)/;


Here's some Python code (tested).

It is not as concise as the Perl code.
Which might or might not be a disadvantage.

Sometimes, regular expressions are not the right thing.
For example, a simple str.startswith() might be better.

What about "add 9999999999999999999999999 99999999999999999999999"?
Maybe we want to catch the error before we get to the do_add.
Can't easily do that with regular expressions.
And what about a variable number of arguments.

If regular expressions are no longer used, the Perl code seems
to loose some of its elegance.


I've been arguing for writing small, simple functions that do something.
This should make testing much easier.
These functions might happen to use regular expressions.


The code below is clearly more flexible.
It's easy, for example, to add a new command.
Just add an entry to dispatch.

The thing I like best about it is the passing of a dict.

===
#!/usr/bin/python

import re

# here we know about functions and patterns
def do_add(arg1, arg2): print "+ %s %s" % (arg1, arg2)
def do_times(arg1, arg2): print "* %s %s" % (arg1, arg2)

add_re = re.compile(r'add (?P<arg1>.*) (?P<arg2>.*)')
times_re = re.compile(r'times (?P<arg1>.*) (?P<arg2>.*)')

def find_add(str):
     match = add_re.match(str)
     if match is None:
         return match
     return match.groupdict()

def find_times(str):
     match = times_re.match(str)
     if match is None:
         return match
     return match.groupdict()


# here we bind everything together
dispatch = [
     (find_add, do_add),
     (find_times, do_times),
     ]

def doit(str):
     for (find, do) in dispatch:
         d = find(str)
         if d is not None:
             return do(**d)
     return None                         # or error

if __name__ == '__main__':

     doit('add this that')
     doit('times this that')

===


Jonathan




More information about the Python-list mailing list