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;