from __future__ import generators import re, sys, os, time def timer(f, *args, **kwargs): start = time.clock() f(*args, **kwargs) return time.clock()-start def obvious(text, pattern=r"\$(.*?)\$"): regex = re.compile(pattern) a = text #for compatibility with solution below found = 1 while found: found = regex.search(text) if found: output = str(eval(found.group(1))) text = text[:found.start()] + output + text[found.end():] ##q = "this $'hello'$ is $'how are'$ around $'you'$ them" ##p = [(x.start(), x.end()) for x in r.finditer(q)] ##o = reduce(lambda o,x: o+x, p, (0,)) + (len(q),) ##c = [x for x in pair(o)] ##print reduce(lambda o,(s,e): o+q[s:e], c,'') ##o = [0] ##map(o.extend, p) ##o += [len(q)] ##c = [x for x in pair(o)] ##print reduce(lambda o,(s,e): o+q[s:e], c,'') ##p = [x.span() for x in r.finditer(q)] ##c = pair(unpair(reduce(unpair, p, [0]), [len(q)])) ##print reduce(lambda o,(s,e): o+q[s:e], c,'') ##reverse = lambda y: (lambda x: ''.join((x.reverse(), x)[1]))(list(y)) ##print map(reverse, x) ##unpair = lambda a: reduce(lambda x,y: x + y, a) ##stringify = lambda x: x is not None and str(x) or '' ##stringify = lambda x: str(x)*(x is not None) ##stringify = lambda x: {None:''}.get(x, str(x)) #fastest: ##d = {None:''} ##stringify = lambda x: d.get(x, str(x)) #chain2 = lambda a,b: lambda x: b(a(x)) #evaluator = lambda q: map(deNone, map(eval, map(match, r.finditer(q)))) ##def pair(l): ## a = iter(l); ## while 1: yield a.next(), a.next() ##pair = lambda a: filter(None, map( lambda x: x[2] and x[:2], zip([None]+a, a, [0,1]*len(a)))) ##pair = lambda a: [x for i,x in enumerate(zip([None]+a,a)) if i&1] #return a list of tuples (index,item) enumerate = lambda x: zip(range(len(x)), x) #collect a linear list to a list of tuples of given size group = lambda items, size: [x for i,x in enumerate(zip(*[[None]*(size-1-x)+items for x in range(size)])) if i%size==size-1] #flatten a list of tuples ungroup = lambda a: reduce(lambda x,y: caret(x.extend, y), a, []) #call method and return the object, useful for builtins, like list which methods don't return self. name from 'call and return' caret = lambda m,*a,**k: (m(*a,**k), m.__self__)[1] #suff function with args for delayed execution curry = lambda f, *a, **k: lambda *aa, **kk: f(*(a+aa), **caret(dict(k).update, kk)) safran = lambda f, *a, **k: lambda *aa, **kk: f(*(aa+a), **caret(dict(k).update, kk)) pair = lambda a: map(lambda x: x[:2], filter(lambda x: x[2], zip([None]+a, a, [0,1]*(len(a)/2)))) chain = lambda *flst: lambda arg: reduce(lambda last, f: f(last), flst, arg) span = lambda x: x.span() takegroup = lambda x: x.group(1) evaluator = lambda matches: map(chain(takegroup, eval, str), matches) cutout = lambda text, matches: reduce(lambda o,(s,e): o + [text[s:e]], pair([0] + ungroup(map(span, matches)) + [len(text)]), []) smart = lambda text: ''.join(ungroup(zip(cutout(text, find(text)), evaluator(find(text)) + ['']))) find = lambda text, pattern=r"\$(.*?)\$": re.compile(pattern).finditer(text) print "-" print smart("Python $sys.version$ is running") print smart("Python $sys.version$ is running on $os.name$") #print smart("$sys.stdout.write(str(text))$") #self printing def test(): ##test cases... for text in ("$''.join([chr(x) for x in range(10)])$"*1000, "$sys.stdout.write(str(a))$"*50, "$str(a).replace('\\x24','@')$"*200): #print repr(text) t1 = timer(smart, text) print "smart: ", t1 t2 = timer(obvious, text) print "obvious:", t2 print "gain obvious/smart", t2/t1 #test()