torna alle lezioni

Analizzate un'espressione

Un’espressione aritmetica consiste in 2 numeri e un operatore tra di essi, ad esempio:

  • 1 + 2
  • 1.2 * 3.4
  • -3 / -6
  • -2 - 2

L’operatore è uno fra: "+", "-", "*" o "/".

Potrebbero esserci ulteriori spazi all’inizio, alla fine o tra gli elementi.

Create una funzione parse(expr) che riceva un’espressione e restituisca un array di 3 elementi:

  1. Il primo numero.
  2. L’operatore.
  3. Il secondo numero.

Ad esempio:

let [a, op, b] = parse("1.2 * 3.4");

alert(a); // 1.2
alert(op); // *
alert(b); // 3.4

L’espressione regolare per un numero è: -?\d+(\.\d+)?. L’abbiamo creata nell’esercizione precedente.

Per trovare un operatore usiamo [-+*/]. Il trattino - va posto all’inizio nelle parentesi quadre, in mezzo significherebbe un intervallo di caratteri, mentre noi vogliamo soltanto il carattere -.

Dovremmo fare l’escape dello slash / dentro una regexp JavaScript /.../, lo faremo dopo.

Abbiamo bisogno di un numero, un operatore, e quindi un altro numero. Tra di essi ci possono essere spazi opzionali.

Ecco l’intera espressione regolare: -?\d+(\.\d+)?\s*[-+*/]\s*-?\d+(\.\d+)?.

Questa consta di 3 parti, intervallate da \s*:

  1. -?\d+(\.\d+)? – il primo numero,
  2. [-+*/] – l’operatore,
  3. -?\d+(\.\d+)? – il secondo numero.

Per rendere ciascuna di queste parti un elemento separato dell’array di risultati le racchiudiamo tra parentesi: (-?\d+(\.\d+)?)\s*([-+*/])\s*(-?\d+(\.\d+)?).

In azione:

let regexp = /(-?\d+(\.\d+)?)\s*([-+*\/])\s*(-?\d+(\.\d+)?)/;

alert( "1.2 + 12".match(regexp) );

Il risultato include:

  • result[0] == "1.2 + 12" (l’intera corrispondenza)
  • result[1] == "1.2" (il primo gruppo (-?\d+(\.\d+)?), il primo numero compresa la parte decimale)
  • result[2] == ".2" (il secondo gruppo(\.\d+)?, la prima parte decimale)
  • result[3] == "+" (il terzo gruppo ([-+*\/]), l’operatore)
  • result[4] == "12" (il quarto gruppo (-?\d+(\.\d+)?), il secondo numero)
  • result[5] == undefined (il quinto gruppo (\.\d+)?, l’ultima parte decimale è assente, quindi equivale ad undefined)

Il nostro scopo è ottenere i numeri e l’operatore, senza l’intera corrispondenza o le parti decimali, quindi “puliamo” un po’ il risultato.

L’intera corrispondenza (il primo elemento dell’array) possiamo rimuoverla con result.shift().

I gruppi che contengono le parti decimali (gli elementi 2 e 4) (.\d+) li escludiamo aggiungendo ?: all’inizio: (?:\.\d+)?.

La soluzione finale:

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