如何对充满数学操作的字符串进行语法检查

3

可能重复:
JavaScript中算术表达式的安全评估

我正在尝试构建一个在线计算器,作为我一直在开发的网站的一部分。

我的操作符包括:+ - * / () AVG MIN MAX sine cos 等等,还有数字、运算符和函数的按钮。我只是将按下的任何按钮附加到一个字符串上。

我必须在UI端构建一个基本的语法检查器。服务器将实际执行操作并存储和显示它们。我不想花太多时间编写客户端代码,但我的想法是验证它是否数学上合理。

这是我的计划:

我将尝试对生成的字符串进行eval()并捕获错误。如果错误是synatxError,则意味着该字符串在语法上是错误的。如果它是任何其他类型的错误,我都可以接受。

所以我在脚本开始时做了这个:

Error.prototype.dummy_attribute = "notSyntaxError"
SyntaxError.prototype.dummy_attribute = "SyntaxError"

上述方法对我不起作用,因为如果有字符串链接2(),我会收到类型错误。现在我必须编写一段代码来检查空括号和没有运算符前置的括号,或者没有运算符后跟的括号。

或者,我是否可以使用替代方法来检查我所拥有的字符串的语法,以查看它是否在数学上有意义。


2
@Jivings 对此编写正则表达式几乎是不可能的。祝你匹配成功开放和关闭括号。而eval()并不总是邪恶的。 - epascarello
顺便说一句:他们是如何为编程语言编写词法分析器的?我迫不及待地想要实现这个简单的东西。 - Ranjith Ramachandra
2
@Jivings,它为什么邪恶?对于使用该页面的人来说是邪恶的。唯一可能会造成伤害的方式是如果人们可以通过链接共享未经验证的方程式。谁在乎用户是否破坏了自己的页面。 - epascarello
@RanjithR 我猜是因为可能有重复的原因。 - Jivings
这很酷。顺便问一下,我该如何构建一个解析器?你能给我一些学习的链接吗? - Ranjith Ramachandra
显示剩余10条评论
1个回答

1

使用eval是可能的。我知道一些死忠的eval反对者会对此进行负面评价。唯一的问题是,如果你让人们在查询字符串中提供一个方程式来链接到你的页面,那么这将使你容易受到XSS攻击。如果你只在当前页面上使用它进行验证,那么这个人只会搞砸自己的页面,不会对其他人造成风险。

基本思路:

function avg () {
    var len = arguments.length;
    if(len===0) {
        throw "no arguments suppulied for AVG";   
    }
    var arr = Array.prototype.slice.call(arguments, 0);   
    var total = 0;
    for (var i=0; i<len; i++) {
        total += arr[i];
    }
    return total/len;
}
function sine (num) {
    return Math.sin(num);
}

function max () {

    var len = arguments.length;
    if(len===0) {
        throw "no arguments suppulied for MAX";      
    }   
    var arr = Array.prototype.slice.call(arguments, 0);
    return Math.max.apply(null, arr);

}


function isValidEqn (eqn) {
    try{
        eval("var x = " + eqn.toLowerCase());
        return !isNaN(x);
    } catch(e) {
        //console.error(e);
        return false;
    }
}



var eqn1 = "AVG ( 2008 , 2000 )";
var eqn2 = "AVG ( 2008 , 2000 ) / 100 + sine(10)";
var eqn3 = "AVG ( 2008 , 2000 ) / 100 + sine(10) + MAX(10,20)";

console.log("sadjhsahd", isValidEqn("sadjhsahd") );
console.log(eqn1, isValidEqn(eqn1) );
console.log(eqn2, isValidEqn(eqn2) );
console.log(eqn3, isValidEqn(eqn3) );

我喜欢这个想法。虽然我不会有任何查询字符串,但生成它的唯一方法是从用户界面(UI)。我猜我需要为所有函数编写虚拟函数来检查参数。 - Ranjith Ramachandra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接