Is there a simple/safe expression evaluator I can use in a python
program. I just want to pass along a string in the form "1 + 44 / 3" or
perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to
the problems with that method.
In this use I don't need python to worry about complex numbers,
variables or anything else. Just do the math on a set of values. Would
eval() with some restricted list of permitted operators do the trick?
I'm feeling too lazy to write/debug my own parser for this :)
Thanks, Bob. 7 1176
On Jun 11, 1:25 pm, bvdp <b...@mellowood.cawrote:
Is there a simple/safe expression evaluator I can use in a python
program. I just want to pass along a string in the form "1 + 44 / 3" or
perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to
the problems with that method.
In this use I don't need python to worry about complex numbers,
variables or anything else. Just do the math on a set of values. Would
eval() with some restricted list of permitted operators do the trick?
I'm feeling too lazy to write/debug my own parser for this :)
Thanks, Bob.
Funny, I need exactly the same kind of parser myself right now.
Fredrik Lundh has posted some code-and-explanation on an excellent
simple parser that's easy to extend. http://effbot.org/zone/simple-iterator-parser.htm
Just make it recognize the operator tokens you're interested in and if
a string parsers w/o errors then you know it's safe to eval().
I probably won't get to writing this myself for a few days or a week,
but if you do will you post it here (or send me a copy)? I'll do the
same if I get to it sooner.
Regards,
~Simon
On Jun 11, 1:25 pm, bvdp <b...@mellowood.cawrote:
Is there a simple/safe expression evaluator I can use in a python
program. I just want to pass along a string in the form "1 + 44 / 3" or
perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to
the problems with that method.
In this use I don't need python to worry about complex numbers,
variables or anything else. Just do the math on a set of values. Would
eval() with some restricted list of permitted operators do the trick?
I'm feeling too lazy to write/debug my own parser for this :)
Thanks, Bob.
Here is something that I wrote using the _ast module. It works pretty
well, and might be a good example for others wanting to experiment
with the _ast module. On a related note... if anybody wants to provide
feedback on this code it would be much appreciated. It involves a lot
of if/elif branches, and feels ugly.
Matt -
import _ast
-
-
class SafeEvalError(Exception):
-
pass
-
-
class UnsafeCode(SafeEvalError):
-
pass
-
-
# safe types:
-
# Sequences:
-
# list, tuple, dict, set, frozen_set*
-
# Literals: str, unicode, int, long, complex, float
-
def safe_eval(text):
-
"similar to eval, but only works on literals"
-
ast = compile(text, "<string>", 'exec', _ast.PyCF_ONLY_AST)
-
return _traverse(ast.body[0].value)
-
-
def _traverse(ast):
-
if isinstance(ast, _ast.List):
-
return [_traverse(el) for el in ast.elts]
-
elif isinstance(ast, _ast.Tuple):
-
return tuple(_traverse(el) for el in ast.elts)
-
elif isinstance(ast, _ast.Dict):
-
return dict(
-
zip(
-
(_traverse(k) for k in ast.keys),
-
(_traverse(v) for v in ast.values)
-
)
-
)
-
elif isinstance(ast, _ast.Str):
-
return ast.s
-
elif isinstance(ast, _ast.Num):
-
return ast.n
-
elif isinstance(ast, _ast.Expr):
-
return _traverse(ast.value)
-
elif isinstance(ast, _ast.BinOp):
-
if isinstance(ast.op, _ast.Add):
-
return _traverse(ast.left) + _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Sub):
-
return _traverse(ast.left) - _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Div):
-
return _traverse(ast.left) / _traverse(ast.right)
-
elif isinstance(ast.op, _ast.FloorDiv):
-
return _traverse(ast.left) // _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Mod):
-
return _traverse(ast.left) % _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Mult):
-
return _traverse(ast.left) * _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Pow):
-
return _traverse(ast.left) ** _traverse(ast.right)
-
elif isinstance(ast.op, _ast.BitAnd):
-
return _traverse(ast.left) & _traverse(ast.right)
-
elif isinstance(ast.op, _ast.BitOr):
-
return _traverse(ast.left) | _traverse(ast.right)
-
elif isinstance(ast.op, _ast.BitXor):
-
return _traverse(ast.left) ^ _traverse(ast.right)
-
elif isinstance(ast.op, _ast.LShift):
-
return _traverse(ast.left) << _traverse(ast.right)
-
elif isinstance(ast.op, _ast.RShift):
-
return _traverse(ast.left) >_traverse(ast.right)
-
elif isinstance(ast, _ast.BoolOp):
-
if isinstance(ast.op, _ast.And):
-
return all(_traverse(v) for v in ast.values)
-
if isinstance(ast.op, _ast.Or):
-
return any(_traverse(v) for v in ast.values)
-
elif isinstance(ast, _ast.UnaryOp):
-
if isinstance(ast.op, _ast.Invert):
-
return _traverse(ast.operand)
-
if isinstance(ast.op, _ast.USub):
-
return -_traverse(ast.operand)
-
if isinstance(ast.op, _ast.UAdd):
-
return +_traverse(ast.operand)
-
if isinstance(ast.op, _ast.Not):
-
return not _traverse(ast.operand)
-
-
-
raise UnsafeCode()
-
-
if __name__ == "__main__":
-
print safe_eval("[1,2,3,{'hello':1}, (1,-2,3)], 4j, 1+5j, ~1+2*3")
-
Matimus wrote:
On Jun 11, 1:25 pm, bvdp <b...@mellowood.cawrote:
>Is there a simple/safe expression evaluator I can use in a python program. I just want to pass along a string in the form "1 + 44 / 3" or perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to the problems with that method.
In this use I don't need python to worry about complex numbers, variables or anything else. Just do the math on a set of values. Would eval() with some restricted list of permitted operators do the trick?
I'm feeling too lazy to write/debug my own parser for this :)
Thanks, Bob.
Here is something that I wrote using the _ast module. It works pretty
well, and might be a good example for others wanting to experiment
with the _ast module. On a related note... if anybody wants to provide
feedback on this code it would be much appreciated. It involves a lot
of if/elif branches, and feels ugly.
Matt
-
import _ast
-
class SafeEvalError(Exception):
-
pass
-
class UnsafeCode(SafeEvalError):
-
pass
-
# safe types:
-
# Sequences:
-
# list, tuple, dict, set, frozen_set*
-
# Literals: str, unicode, int, long, complex, float
-
def safe_eval(text):
-
"similar to eval, but only works on literals"
-
ast = compile(text, "<string>", 'exec', _ast.PyCF_ONLY_AST)
-
return _traverse(ast.body[0].value)
-
def _traverse(ast):
-
if isinstance(ast, _ast.List):
-
return [_traverse(el) for el in ast.elts]
-
elif isinstance(ast, _ast.Tuple):
-
return tuple(_traverse(el) for el in ast.elts)
-
elif isinstance(ast, _ast.Dict):
-
return dict(
-
zip(
-
(_traverse(k) for k in ast.keys),
-
(_traverse(v) for v in ast.values)
-
)
-
)
-
elif isinstance(ast, _ast.Str):
-
return ast.s
-
elif isinstance(ast, _ast.Num):
-
return ast.n
-
elif isinstance(ast, _ast.Expr):
-
return _traverse(ast.value)
-
elif isinstance(ast, _ast.BinOp):
-
if isinstance(ast.op, _ast.Add):
-
return _traverse(ast.left) + _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Sub):
-
return _traverse(ast.left) - _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Div):
-
return _traverse(ast.left) / _traverse(ast.right)
-
elif isinstance(ast.op, _ast.FloorDiv):
-
return _traverse(ast.left) // _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Mod):
-
return _traverse(ast.left) % _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Mult):
-
return _traverse(ast.left) * _traverse(ast.right)
-
elif isinstance(ast.op, _ast.Pow):
-
return _traverse(ast.left) ** _traverse(ast.right)
-
elif isinstance(ast.op, _ast.BitAnd):
-
return _traverse(ast.left) & _traverse(ast.right)
-
elif isinstance(ast.op, _ast.BitOr):
-
return _traverse(ast.left) | _traverse(ast.right)
-
elif isinstance(ast.op, _ast.BitXor):
-
return _traverse(ast.left) ^ _traverse(ast.right)
-
elif isinstance(ast.op, _ast.LShift):
-
return _traverse(ast.left) << _traverse(ast.right)
-
elif isinstance(ast.op, _ast.RShift):
-
return _traverse(ast.left) >_traverse(ast.right)
-
elif isinstance(ast, _ast.BoolOp):
-
if isinstance(ast.op, _ast.And):
-
return all(_traverse(v) for v in ast.values)
-
if isinstance(ast.op, _ast.Or):
-
return any(_traverse(v) for v in ast.values)
-
elif isinstance(ast, _ast.UnaryOp):
-
if isinstance(ast.op, _ast.Invert):
-
return _traverse(ast.operand)
-
if isinstance(ast.op, _ast.USub):
-
return -_traverse(ast.operand)
-
if isinstance(ast.op, _ast.UAdd):
-
return +_traverse(ast.operand)
-
if isinstance(ast.op, _ast.Not):
-
return not _traverse(ast.operand)
-
raise UnsafeCode()
-
if __name__ == "__main__":
-
print safe_eval("[1,2,3,{'hello':1}, (1,-2,3)], 4j, 1+5j, ~1+2*3")
-
Oh, this is interesting. Similar to some other code I found on the web
which grabs a list of permitted token values using the dis module: http://aspn.activestate.com/ASPN/Coo.../Recipe/286134
I was really hoping for a builtin on this :)
Thanks.
Simon Forman wrote:
On Jun 11, 1:25 pm, bvdp <b...@mellowood.cawrote:
>Is there a simple/safe expression evaluator I can use in a python program. I just want to pass along a string in the form "1 + 44 / 3" or perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to the problems with that method.
In this use I don't need python to worry about complex numbers, variables or anything else. Just do the math on a set of values. Would eval() with some restricted list of permitted operators do the trick?
I'm feeling too lazy to write/debug my own parser for this :)
Thanks, Bob.
Funny, I need exactly the same kind of parser myself right now.
Fredrik Lundh has posted some code-and-explanation on an excellent
simple parser that's easy to extend. http://effbot.org/zone/simple-iterator-parser.htm
Just make it recognize the operator tokens you're interested in and if
a string parsers w/o errors then you know it's safe to eval().
I probably won't get to writing this myself for a few days or a week,
but if you do will you post it here (or send me a copy)? I'll do the
same if I get to it sooner.
Regards,
~Simon
I'll have to read Fredrik's code a few more times, but I think it makes
as much sense as anything else. Of course, I could take the lazy man's
way out and just to a left->right evaluation without any ()s, etc.,
which in my project would work. But, honestly, I thought it'd be easier.
I was going to use eval() until I realized that it was not a good idea.
Darn shame we have to work so hard to prevent some jerk's malicious code
from effecting our stuff. Oh well, that's life.
On Jun 11, 3:25*pm, bvdp <b...@mellowood.cawrote:
Is there a simple/safe expression evaluator I can use in a python
program. I just want to pass along a string in the form "1 + 44 / 3" or
perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to
the problems with that method.
In this use I don't need python to worry about complex numbers,
variables or anything else. Just do the math on a set of values. Would
eval() with some restricted list of permitted operators do the trick?
I'm feeling too lazy to write/debug my own parser for this :)
Thanks, Bob.
This example ships with pyparsing, and can be extended to support
built-in functions: http://pyparsing.wikispaces.com/spac...mage/fourFn.py.
-- Paul
bvdp wrote:
>
Is there a simple/safe expression evaluator I can use in a python
program. I just want to pass along a string in the form "1 + 44 / 3" or
perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to
the problems with that method.
In this use I don't need python to worry about complex numbers,
variables or anything else. Just do the math on a set of values. Would
eval() with some restricted list of permitted operators do the trick?
This solution may be overly simply (especially compared to the AST-based
solution suggested earlier), but... if all you need is numbers and operators,
*maybe* you can get away with stripping all letters from the input string (and
possibly the underscore), and then evaluating it:
import re
import traceback
re_letters = re.compile("[a-zA-Z_]+")
def safe_eval(s):
s = re_letters.sub("", s)
return eval(s)
# try it out...
>>safe_eval("2+2")
4
>>safe_eval("4 * (8 / 3.1) ** 7.2")
3685.5618352828474
>>safe_eval("(2).__class__.__base__.__subclasses__ ()")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "safe_eval.py", line 12, in safe_eval
return eval(s)
File "<string>", line 1
(2)...()
^
SyntaxError: invalid syntax
....It's primitive, but it might work for your purposes.
--
Hans Nowak (zephyrfalcon at gmail dot com) http://4.flowsnake.org/
On 2008-06-12, Hans Nowak <ze*******************@gmail.comwrote:
bvdp wrote:
>> Is there a simple/safe expression evaluator I can use in a python program. I just want to pass along a string in the form "1 + 44 / 3" or perhaps "1 + (-4.3*5)" and get a numeric result.
I can do this with eval() but I really don't want to subject my users to the problems with that method.
In this use I don't need python to worry about complex numbers, variables or anything else. Just do the math on a set of values. Would eval() with some restricted list of permitted operators do the trick?
This solution may be overly simply (especially compared to the
AST-based solution suggested earlier), but... if all you need
is numbers and operators, *maybe* you can get away with
stripping all letters from the input string (and possibly the
underscore), and then evaluating it:
It won't work for numbers expressed in scientific notation
(e.g. 1.23e-3).
--
Grant Edwards grante Yow! All right, you
at degenerates! I want
visi.com this place evacuated in
20 seconds! This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: bvdp |
last post by:
I'm finding my quest for a safe eval() quite frustrating :)
Any comments on this: Just forget about getting python to do this and,
instead, grab my set of values (from a user supplied text file)...
|
by: bvdp |
last post by:
Okay guys. I have the _ast based safe eval installed and working in my
program. It appears to be working just fine. Thanks for the help.
Now, a few more questions:
1. I see that _ast is a 2.5...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
| |