レッスンに戻る

式を解析する

算術式は、2つの数値とそれらの間の演算子で構成されます。例えば

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

演算子は、"+""-""*"、または"/"のいずれかです。

先頭、末尾、または部分の間には、余分なスペースがある場合があります。

式を受け取り、3つの要素の配列を返す関数parse(expr)を作成します。

  1. 最初の数値。
  2. 演算子。
  3. 2番目の数値。

例えば

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

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

数値の正規表現は次のとおりです。 -?\d+(\.\d+)?。これは前の課題で作成しました。

演算子は[-+*/]です。-は角括弧の先頭にきます。なぜなら、中央にあると文字範囲を意味する一方、ここでは単なる文字-を意図しているからです。

スラッシュ/はJavaScript正規表現/.../内でエスケープする必要があります。後で処理します。

数値、演算子、そしてもう1つの数値が必要です。それらの間には任意のスペースを含めることができます。

完全な正規表現:-?\d+(\.\d+)?\s*[-+*/]\s*-?\d+(\.\d+)?

これは\s*を間に挟んだ3つの部分から構成されています。

  1. -?\d+(\.\d+)? – 最初の数値。
  2. [-+*/] – 演算子。
  3. -?\d+(\.\d+)? – 2番目の数値。

これらの各部分を結果配列の個別の要素にするには、括弧で囲みます。(-?\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"(2番目のグループ(\.\d+)? – 最初の小数部)
  • result[3] == "+"(3番目のグループ([-+*\/]) – 演算子)
  • result[4] == "12"(4番目のグループ(-?\d+(\.\d+)?) – 2番目の数値)
  • result[5] == undefined(5番目のグループ(\.\d+)? – 最後小数部がないため、undefined)

数値と演算子のみが必要で、完全一致や小数部は不要であるため、結果を少し「クリーンアップ」します。

完全一致(配列の最初の要素)は、配列をシフトすることで削除できますresult.shift()

小数部を含むグループ(2番目と5番目)(.\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;