1

I have a file with a lot of lines like this

f(a, b)
f(abc, def)
f(a, f(u, i))
...

and I was asked to write a program in Python that would translate the strings into the following format:

a+b
abc+def
a+(u+i)
...

Rule: f(a, b) -> a+b

The approach I am following right now uses eval functions:

def f(a, b):
    return "({0} + {1})".format(a,b)

eval("f(f('b','a'),'c')")

which returns

'((b + a) + c)'

However, as you can see, I need to put the letters as strings so that the eval function does not throw me a NameError when I run it.

Is there any way that will allow me to get the same behavior out of the eval function but without declaring the letters as strings?

9
  • I don't think you want to use eval for this. Besides, it's generally unsafe to do. Commented May 5, 2014 at 15:21
  • @2rs2ts If it is a secure environment (f.e. homework on a virtual machine), it can be done. Commented May 5, 2014 at 15:22
  • 1
    Using ast.literal_eval() is a little safer: docs.python.org/2/library/ast.html#ast.literal_eval. Commented May 5, 2014 at 15:26
  • @nofinator Wouldn't be useful for this case, though, since those aren't python literals. Commented May 5, 2014 at 15:28
  • Have you think to use regex ? Commented May 5, 2014 at 15:29

3 Answers 3

2

eval is overkill here. this is just a simple string processing exercise:

  • replace the first 'f(' and the last ')' with ''
  • replace all remaining 'f(' with '('
  • replace all ', ' with '+'

and you're done.

this assumes that the only time the characters 'f(' appear next to each other is when it's supposed to represent a call to function f.

Sign up to request clarification or add additional context in comments.

2 Comments

so simple! I should have remembered that. Thanks!
no prob. sometimes it's easy to overlook the simple for the complicated.
2

Yes, you can. The key is to use a mapping which returns the string as a key when it is missing.

>>> class Mdict(dict):
...     def __missing__(self, k):
...         return k
... 
>>> eval('foo + bar', Mdict())
'foobar'

Of course, the general caveats about eval apply -- Please don't use it unless you trust the input completely.

2 Comments

What about eval('abc + def')?
@frostnational -- unfortunately, there's absolutely nothing you can do about that since it is a SyntaxError and python can't parse it into an AST. All you can do there is eval('abc + "def"') -- Or use something other than eval.
1

You could use the shlex module to give yourself a nice token stack and then parse it as a sort of push down automaton.

>>> import shlex
>>> def parsef(tokens):
    ftok = tokens.get_token()       # there's no point to naming these tokens
    oparentok = tokens.get_token()  # unless you want to assert correct syntax
    lefttok = tokens.get_token()
    if 'f' == lefttok:
        tokens.push_token(lefttok)
        lefttok = "("+parsef(tokens)+")"
    commatok = tokens.get_token()
    righttok = tokens.get_token()
    if 'f' == righttok:
        tokens.push_token(righttok)
        righttok = "("+parsef(tokens)+")"
    cparentok = tokens.get_token()
    return lefttok+"+"+righttok
>>> def parseline(line):
    return parsef(shlex.shlex(line.strip()))
>>> parseline('f(a, b)')
'a+b'
>>> parseline('f(abc, def)')
'abc+def'
>>> parseline('f(a, f(u, i))')
'a+(u+i)'

Note that this assumes you are getting correct syntax.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.