解析表达式
算术表达式由两个数字和它们之间的运算符组成,例如
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+)?
– 最后一个十进制部分不存在,因此未定义)
我们只需要数字和运算符,不需要完全匹配或小数部分,所以让我们稍微“清理”一下结果。
完全匹配(数组的第一个项目)可以通过移位数组 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;