9

我只需要使用 python 检查字符串是否是有效的数学表达式。

为简单起见,假设我只需要带有数字和嵌套括号的运算+ - * /符(+ -也是一元的)。为了完整起见,我还添加了简单的变量名。

所以我可以这样测试:

test("-3 * (2 + 1)") #valid
test("-3 * ")        #NOT valid

test("v1 + v2")      #valid
test("v2 - 2v")      #NOT valid ("2v" not a valid variable name)

我尝试了 pyparsing,但只是尝试了以下示例:“执行+,-,*,/^算术运算的简单代数表达式解析器”我传递了无效代码并试图修复它我总是得到错误的语法被解析而没有引发异常

试试看

>>>test('9', 9)
9 qwerty = 9.0 ['9'] => ['9']
>>>test('9 qwerty', 9)
9 qwerty = 9.0 ['9'] => ['9']

两个测试都通过... o_O

有什么建议吗?

4

5 回答 5

3

这是因为 pyparsing 代码允许函数。(顺便说一句,它做的比你需要的要多得多,即创建一个堆栈并对其进行评估。)

对于初学者,您可以从代码中删除piident(可能还有我现在缺少的其他内容)以禁止字符。

原因不同:PyParsing 解析器默认不会尝试使用整个输入。如果它无法解析整个输入,您必须添加+ StringEnd()(并导入它,当然)到末尾以使其失败。expr在这种情况下,pyparsing.ParseException将提出。(来源: http: //pyparsing-public.wikispaces.com/FAQs

如果你想学习一点解析,你需要的东西可以用任何像样的解析库(我喜欢LEPL)在不到 30 行的时间内构建。

于 2011-02-03T15:09:18.513 回答
2

为什么不直接评估它并捕获语法错误呢?

from math import *

def validateSyntax(expression):
  functions = {'__builtins__': None}
  variables = {'__builtins__': None}

  functions = {'acos': acos,
               'asin': asin,
               'atan': atan,
               'atan2': atan2,
               'ceil': ceil,
               'cos': cos,
               'cosh': cosh,
               'degrees': degrees,
               'exp': exp,
               'fabs':fabs,
               'floor': floor,
               'fmod': fmod,
               'frexp': frexp,
               'hypot': hypot,
               'ldexp': ldexp,
               'log': log,
               'log10': log10,
               'modf': modf,
               'pow': pow,
               'radians': radians,
               'sin': sin,
               'sinh': sinh,
               'sqrt': sqrt,
               'tan': tan,
               'tanh': tanh}

  variables = {'e': e, 'pi': pi}

  try:
    eval(expression, variables, functions)
  except (SyntaxError, NameError, ZeroDivisionError):
    return False
  else:
    return True

以下是一些示例:

> print validSyntax('a+b-1') # a, b are undefined, so a NameError arises.
> False

> print validSyntax('1 + 2')
> True

> print validSyntax('1 - 2')
> True

> print validSyntax('1 / 2')
> True

> print validSyntax('1 * 2')
> True

> print validSyntax('1 +/ 2')
> False

> print validSyntax('1 + (2')
> False

> print validSyntax('import os')
> False

> print validSyntax('print "asd"')
> False

> print validSyntax('import os; os.delete("~\test.txt")')
> False # And the file was not removed

它仅限于数学运算,因此它应该比粗略的eval.

于 2011-02-03T15:14:50.037 回答
1

您可以尝试自己构建一个简单的解析器来标记算术表达式的字符串,然后构建一个表达式树,如果树是有效的(叶子都是操作数,内部节点都是运算符),那么您可以说表达式是有效的。

基本概念是制作一些帮助函数来创建解析器。

def extract()将从
def peek()类似于提取的表达式中获取下一个字符,但如果没有空格来检查下一个字符,则使用它
get_expression()
get_next_token()

或者,如果您可以保证字符之间有空格,您可以使用它split()来进行所有标记化。

然后你建立你的树并评估它的结构是否正确

试试这个以获得更多信息:http ://effbot.org/zone/simple-top-down-parsing.htm

于 2011-02-03T15:21:58.857 回答
1

添加parseAll=True到调用parseString会将此解析器转换为验证器。

于 2011-02-03T23:14:08.397 回答
0

如果您有兴趣修改用 Python 编写的自定义数学评估器引擎​​,使其改为验证器,您可以从Evaluator 2.0 (Python 3.x) 和Math_Evaluator (Python 2.x) 开始。它们不是现成的解决方案,但可以让您完全自定义您尝试使用(希望)易于阅读的 Python 代码所做的任何事情。请注意,“and”和“or”被视为运算符。

于 2011-02-04T02:31:34.997 回答