regresar a la lección

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:

  1. El primer número.
  2. El operador.
  3. 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:

  1. -?\d+(\.\d+)? – el primer número,
  2. [-+*/] – el operador,
  3. -?\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;