式を解析する
算術式は、2つの数値とそれらの間の演算子で構成されます。例えば
1 + 2
1.2 * 3.4
-3 / -6
-2 - 2
演算子は、"+"
、"-"
、"*"
、または"/"
のいずれかです。
先頭、末尾、または部分の間には、余分なスペースがある場合があります。
式を受け取り、3つの要素の配列を返す関数parse(expr)
を作成します。
- 最初の数値。
- 演算子。
- 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つの部分から構成されています。
-?\d+(\.\d+)?
– 最初の数値。[-+*/]
– 演算子。-?\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;