解析表达式
算术表达式由两个数字和它们之间的运算符组成,例如
1 + 21.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+)?– 最后一个十进制部分不存在,因此未定义)
我们只需要数字和运算符,不需要完全匹配或小数部分,所以让我们稍微“清理”一下结果。
完全匹配(数组的第一个项目)可以通过移位数组 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
作为使用非捕获组 ?: 的替代方案,我们可以像这样命名组
function parse(expr) {
let regexp = /(?<a>-?\d+(?:\.\d+)?)\s*(?<operator>[-+*\/])\s*(?<b>-?\d+(?:\.\d+)?)/;
let result = expr.match(regexp);
return [result.groups.a, result.groups.operator, result.groups.b];
}
alert( parse("-1.23 * 3.45") ); // -1.23, *, 3.45;