用Python编写的数学语法检查器
我只需要用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
有什么建议吗?
5 个回答
你可以尝试自己写一个简单的解析器,来把算术表达式的字符串分解成一个个小部分,然后构建一个表达式树。如果这个树是有效的(也就是说,树的叶子节点都是操作数,内部节点都是运算符),那么你就可以说这个表达式是有效的。
基本的思路是创建一些辅助函数来帮助你构建解析器。
def extract()
这个函数会从表达式中获取下一个字符。
def peek()
这个函数和extract类似,但它用来检查下一个字符,如果没有空格的话。
get_expression()
get_next_token()
另外,如果你能保证字符之间有空格的话,可以使用 split()
来完成所有的分解工作。
然后你就可以构建你的树,并检查它的结构是否正确。
想了解更多信息,可以试试这个链接: http://effbot.org/zone/simple-top-down-parsing.htm
在调用 parseString
时,如果加上 parseAll=True
,那么这个解析器就会变成一个验证器。
这是因为pyparsing的代码允许使用函数。(顺便说一下,它的功能比你需要的要多很多,比如创建一个栈并进行计算。)
首先,你可以从代码中去掉pi
和ident
(可能还有其他我现在想不起来的东西),这样就不允许使用这些字符了。
原因其实不同:PyParsing的解析器默认不会尝试处理整个输入。你需要在expr
的末尾添加+ StringEnd()
(当然也要导入它),这样如果它不能解析整个输入就会失败。在这种情况下,会抛出pyparsing.ParseException
的错误。(来源:http://pyparsing-public.wikispaces.com/FAQs)
如果你想了解一些解析的知识,使用任何一个不错的解析库,你需要的功能可能不到三十行代码就能实现(我个人喜欢LEPL)。