给出一个字符串:
var str1 = "25*5+5*7";
如果不使用JavaScript中的eval
或构造函数,我怎样才能编写一个名为“output”的函数,该函数接收字符串并输出字符串的算术值,在本例中为160 ?
答案 0 :(得分:11)
这里是递归解析后的完整优先级表达式求值程序 我在OP的问题评论中链接到了这个想法。
为此,首先我为我想要处理的表达式写了一个简单的BNF语法:
sum = product | sum "+" product | sum "-" product ;
product = term | product "*" term | product "/" term ;
term = "-" term | "(" sum ")" | number ;
这本身需要一些简单而直接的经验。如果您没有BNF的经验,您会发现 它非常适用于描述复杂的项目流,如表达式,消息,编程语言......
使用该语法,我按照其他消息中列出的步骤进行操作 生成以下代码。显而易见的是,它是以一种愚蠢的机械方式由语法驱动的,因此如果你有这种语法就很容易写出来。
(未经测试。我不是JavaScript编码器。这肯定会包含一些语法/语义问题。我花了大约15分钟来编写代码。)
var SE="Syntax Error";
function parse(str) { // returns integer expression result or SE
var text=str;
var scan=1;
return parse_sum();
function parse_sum() {
var number, number2;
if (number=parse_product()==SE) return SE;
while (true) {
skip_blanks();
if (match("+") {
number2=parse_product();
if (number2==SE) return SE;
number+=number2;
}
else if (match('-')) {
{ number2=parse_product();
if (number2==SE) return SE;
number-=number2;
}
else return number;
}
}
function parse_product() {
var number, number2;
if (number=parse_number()==SE) return SE;
while (true) {
if (match("*") {
number2=parse_term();
if (number2==SE) return SE;
number*=number2;
}
else if (match('/')) {
number2=parse_term();
if (number2==SE) return SE;
number/=number2;
}
else return number;
}
}
function parse_term() {
var number;
skip_blanks();
if (match("(")) {
number=parse_sum();
if (number=SE) return SE;
skip_blanks();
if (!match(")") return SE;
}
else if match("-") {
number= - parse_term();
}
else if (number=parse_number()==SE) return SE;
return number;
}
function skip_blanks() {
while (match(" ")) { };
return;
}
function parse_number() {
number=0;
if (is_digit()) {
while (is_digit()) {}
return number;
}
else return SE;
}
var number;
function is_digit() { // following 2 lines are likely wrong in detail but not intent
if (text[scan]>="0" && text[scan]<="9") {
number=number*10+text[scan].toInt();
return true;
}
else return false;
}
function match(c) {
if (text[scan]==c)
{ scan++; return true }
else return false;
}
}
编写此类解析器/评估程序非常简单。请参阅my SO answer on how to build a parser(链接到如何构建评估者)。
答案 1 :(得分:2)
这是一个带* over +优先级的简单解析器。我试图让它尽可能具有教育意义。我会留给你添加除法和减法。或括号,如果你特别雄心勃勃。
function parse(str) {
var signs = ["*", "+"]; // signs in the order in which they should be evaluated
var funcs = [multiply, add]; // the functions associated with the signs
var tokens = str.split(/\b/); // split the string into "tokens" (numbers or signs)
for (var round = 0; round < signs.length; round++) { // do this for every sign
alert("tokens at this point: " + tokens.join(" "));
for (var place = 0; place < tokens.length; place++) { // do this for every token
if (tokens[place] == signs[round]) { // a sign is found
var a = parseInt(tokens[place - 1]); // convert previous token to number
var b = parseInt(tokens[place + 1]); // convert next token to number
var result = funcs[round](a, b); // call the appropriate function
alert("calculating: " + a + signs[round] + b + "=" + result);
tokens[place - 1] = result.toString(); // store the result as a string
tokens.splice(place--, 2); // delete obsolete tokens and back up one place
}
}
}
return tokens[0]; // at the end tokens[] has only one item: the result
function multiply(x, y) { // the functions which actually do the math
return x * y;
}
function add(x, y) { // the functions which actually do the math
return x + y;
}
}
var str = "25*5+5*7";
alert("result: " + str + " = " + parse(str));
答案 2 :(得分:1)
您可以使用math.js的表达式解析器:
irb> 5.times { Coaster.insert(name: "Coaster A") }
irb> 4.times { Coaster.insert(name: "Coaster B") }
irb> Coaster.latest.find_by(name: "Coaster A").version
(2.2ms) SELECT COUNT(*) FROM "coasters" WHERE "coasters"."original_version_id" = $1 AND (id <= 11) [["original_version_id", 7]]
=> 5
irb> Coaster.original.find_by(name: "Coaster A").version
(2.3ms) SELECT COUNT(*) FROM "coasters" WHERE "coasters"."original_version_id" = $1 AND (id <= 7) [["original_version_id", 7]]
=> 1
&#13;
var str1= "25*5+5*7"
document.write(str1 + ' = ' + math.eval(str1));
// output: "25*5+5*7 = 160"
&#13;
答案 3 :(得分:-1)
您可以创建一个新脚本:
function parse(str) {
var s = document.createElement('script');
s.text = "window.result = " + str;
document.body.appendChild(s); // Run script
document.body.removeChild(s); // Clean up
return result; // Return the result
}
document.body.innerHTML = parse("5*5+5*5");
或使用事件处理程序内容属性:
function parse(str) {
var el = document.createElement('div');
el.setAttribute('onclick', "this.result = " + str);
el.onclick(); // Run script
return el.result; // Return the result
}
document.body.innerHTML = parse("5*5+5*5");
请注意,这些方法不安全,像eval
一样邪恶但更丑陋。所以我不推荐它们。