quiz about symbolic manipulation

Bengt Richter bokr at oz.net
Sat Dec 14 00:43:05 EST 2002


On 14 Dec 2002 00:05:19 GMT, bokr at oz.net (Bengt Richter) wrote:
[ ... first version substitute routine ...]
> 'square(square(x+y)+z)+square(x+w)'
> >>> substitute(e, 'square','(%s)**2')
> '((x+y)**2+z)**2+(x+w)**2'
>
>Well, this is not so exciting for functions with multiple parameters. How
>might you want to rewrite those? Probably isolate terms and rewrite each term
>and then feed that as a tuple to a rewfmt? If you can assume no terms containing
>nested commas (probably reasonable for math expressions) then it shouldn't be
>too hard. But much beyond that and you may want to use the Python parser after all ;-)
>
>Anyway, I'll leave the rest as an exercise ;-)

It was such a jellybean project I couldn't resist modding it a it to handle
comma separated function args, and multiple functions:

====< simiosub.py >=======================================
# simiosub.py
# a program to rewrite function calls in an expression

from __future__ import generators
import tokenize, StringIO, token

def tokens(expr):
    tokens = tokenize.generate_tokens(StringIO.StringIO(expr).readline)
    return [t[1] for t in tokens]

def substitute(expr, **funs):
    def funrew(expr, funs):
        if isinstance(expr, str): toks = tokens(expr)
        else: toks = expr
        while toks:
            if toks[0] not in funs:
                yield toks.pop(0)
                continue
            currfun = toks.pop(0)
            # find and process parenthesized call parameter expression
            i = ump = 0
            for t in toks:
                i += 1
                if t =='(': ump += 1
                if t == ')':
                    ump -= 1
                    if not ump: break
            rest = toks[i:]
            parenexp = toks[1:i-1]
            ixcommas = [t[1] for t in zip(parenexp,range(len(parenexp)))
                       if t[0]==',']+[len(parenexp)]
            j = 0; paramlist= []
            for k in ixcommas:
                paramlist.append(''.join(funrew(parenexp[j:k], funs)))
                j = k+1
            yield (funs[currfun] % tuple(paramlist))
            toks = rest
            
    return ''.join(funrew(expr, funs))

e = 'square(square(x+y)+z)+square(x+w)'
# substitute(e, 'square','(%s)**2')
if __name__ == '__main__':
    import sys
    args = sys.argv[1:]
    if not args: args = ['square(square(x+y)+z)+square(x+w)', 'square=(%s)**2']
                        # should return '((x+y)**2+z)**2+(x+w)**2'
    e = args.pop(0); funs = dict(map(lambda x: tuple(x.split('=')),args))
    
    print 'before:', e
    for sub in args: print '   ',sub
    print ' after:', substitute(e, **funs)
==========================================================

Default test:

[21:44] C:\pywk\clp>simiosub.py
before: square(square(x+y)+z)+square(x+w)
    square=(%s)**2
 after: ((x+y)**2+z)**2+(x+w)**2

A little more complex:

[21:44] C:\pywk\clp>simiosub.py foo(x*y)+zeep(1,foo(2),3) "foo=(foo %s)" "zeep=(zeep %s %s %s)"
before: foo(x*y)+zeep(1,foo(2),3)
    foo=(foo %s)
    zeep=(zeep %s %s %s)
 after: (foo x*y)+(zeep 1 (foo 2) 3)

Regards,
Bengt Richter



More information about the Python-list mailing list