Analizar una expresión:
Una expresión aritmética consta de 2 números y un operador entre ellos, por ejemplo:
1 + 2
1.2 * 3.4
-3 / -6
-2 - 2
El operador es uno de estos: "+"
, "-"
, "*"
o "/"
.
Puede haber espacios adicionales al principio, al final o entre las partes.
Crea una función parse(expr)
que tome una expresión y devuelva un array de 3 ítems:
- El primer número.
- El operador.
- El segundo número.
Por ejemplo:
let
[
a,
op,
b]
=
parse
(
"1.2 * 3.4"
)
;
alert
(
a)
;
// 1.2
alert
(
op)
;
// *
alert
(
b)
;
// 3.4
Una expresión regular para un número es: -?\d+(\.\d+)?
. La creamos en tareas anteriores.
Un operador es [-+*/]
. El guión -
va primero dentro de los corchetes porque colocado en el medio significaría un rango de caracteres, cuando nosotros queremos solamente un carácter -
.
La barra inclinada /
debe ser escapada dentro de una expresión regular de JavaScript /.../
, eso lo haremos más tarde.
Necesitamos un número, un operador y luego otro número. Y espacios opcionales entre ellos.
La expresión regular completa: -?\d+(\.\d+)?\s*[-+*/]\s*-?\d+(\.\d+)?
.
Tiene 3 partes, con \s*
en medio de ellas:
-?\d+(\.\d+)?
– el primer número,[-+*/]
– el operador,-?\d+(\.\d+)?
– el segundo número.
Para hacer que cada una de estas partes sea un elemento separado del array de resultados, encerrémoslas entre paréntesis: (-?\d+(\.\d+)?)\s*([-+*/])\s*(-?\d+(\.\d+)?)
.
En acción:
let
regexp =
/
(-?\d+(\.\d+)?)\s*([-+*\/])\s*(-?\d+(\.\d+)?)
/
;
alert
(
"1.2 + 12"
.
match
(
regexp)
)
;
El resultado incluye:
result[0] == "1.2 + 12"
(coincidencia completa)result[1] == "1.2"
(primer grupo(-?\d+(\.\d+)?)
– el primer número, incluyendo la parte decimal)result[2] == ".2"
(segundo grupo(\.\d+)?
– la primera parte decimal)result[3] == "+"
(tercer grupo([-+*\/])
– el operador)result[4] == "12"
(cuarto grupo(-?\d+(\.\d+)?)
– el segundo número)result[5] == undefined
(quinto grupo(\.\d+)?
– la última parte decimal no está presente, por lo tanto es indefinida)
Solo queremos los números y el operador, sin la coincidencia completa o las partes decimales, así que “limpiemos” un poco el resultado.
La coincidencia completa (el primer elemento del array) se puede eliminar cambiando el array result.shift()
.
Los grupos que contengan partes decimales (número 2 y 4) (.\d+)
pueden ser excluídos al agregar ?:
al comienzo: (?:\.\d+)?
.
La solución final:
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
Como alternativa al uso de la exclusión de captura ?:
, podemos dar nombre a los grupos:
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;