解析表达式
一个算术表达式由 2 个数字和一个它们之间的运算符组成,例如:
1 + 2
1.2 * 3.4
-3 / -6
-2 - 2
运算符为 "+"
、"-"
、"*"
或 "/"
中之一。
在开头、之间的部分或末尾可能有额外的空格。
创建一个函数 parse(expr)
,它接受一个表达式作为参数,并返回一个包含 3 个元素的数组:
- 第一个数字
- 运算符
- 第二个数字
用例:
let [a, op, b] = parse("1.2 * 3.4");
alert(a); // 1.2
alert(op); // *
alert(b); // 3.4
匹配数字的正则表达式:-?\d+(\.\d+)?
。我们在上一题创建了这个表达式。
我们可以使用 [-+*/]
匹配运算符。连字符 -
在方括号中的最前面,因为在中间它表示字符范围,而我们只想让其表示字符 -
。
在 JavaScript 正则表达式 /.../
中,我们应该对 /
进行转义,稍后我们会对其进行处理。
我们需要一个数字、一个运算符以及另一个数字。其间可能会有空格。
完整的正则表达式为:-?\d+(\.\d+)?\s*[-+*/]\s*-?\d+(\.\d+)?
。
它包含 3 个部分,以 \s*
分隔:
-?\d+(\.\d+)?
—— 第一个数字,[-+*/]
—— 运算符,-?\d+(\.\d+)?
—— 第二个数字。
为了使这里的每一部分成为结果数组中的单独元素,所以我们把它们括在括号里:(-?\d+(\.\d+)?)\s*([-+*/])\s*(-?\d+(\.\d+)?)
。
使用示例:
let regexp = /(-?\d+(\.\d+)?)\s*([-+*\/])\s*(-?\d+(\.\d+)?)/;
alert( "1.2 + 12".match(regexp) );
结果包括:
result[0] == "1.2 + 12"
(完整的匹配项)result[1] == "1.2"
(第一组(-?\d+(\.\d+)?)
—— 第一个数字,包括小数部分)result[2] == ".2"
(第二组(\.\d+)?
—— 第一个数字的小数部分)result[3] == "+"
(第三组([-+*\/])
—— 运算符)result[4] == "12"
(第四组(-?\d+(\.\d+)?)
—— 第二个数字)result[5] == undefined
(第五组(\.\d+)?
—— 第二个数字的小数部分不存在,所以这里是 undefined)
我们只想要数字和运算符,不需要完全匹配的以及小数部分结果,所以让我们稍微“清理”一下结果。
我们可以使用数组的 shift
方法 result.shift()
来删去完全匹配的结果(数组的第一项)。
可以通过在开头添加 ?:
来排除包含小数部分(数字 2 和 4)(.\d+)
的组:(?:\.\d+)?
。
最终的解决方案:
function parse(expr) {
let regexp = /(-?\d+(?:\.\d+)?)\s*([-+*\/])\s*(-?\d+(?:\.\d+)?)/;
let result = expr.match(regexp);
if (!result) return [];
result.shift();
return result;
}
alert( parse("-1.23 * 3.45") ); // -1.23, *, 3.45