JavaScriptで電卓を作る②
「➖(マイナス)」を符号か演算子か正しく扱う」 🧮
こんにちは。tushiko23 です 👋
今回は、前回の記事の続きとして -(マイナス)の入力処理と計算処理 について書いていきます。
👉 前回の記事はこちら JavaScriptで電卓を作る①
今回やること 🧩
電卓を実装していると、- はとても厄介です。
3 - 1 の - → 引き算(演算子)
2 × -4 の - → 符号(マイナス)
今回はこの
👉 「-を演算子として扱うのか、符号として扱うのか」
を正しく判定する仕組みを実装していきます。
マイナス以外の演算子の方針 ✖️➗
まずは前提ルールです。
-
画面上では
× ÷を表示 -
内部計算では
* /を使う -
演算子が連続で押された場合は 最後の演算子で上書き
例 3 → + → 3+ → × → 3×
演算子入力の処理(前回の復習)📥
function inputOperator(op) {
const value = display.value;
const lastRaw = value.slice(-1);
if (value === "0では除算できません") {
display.value = "0";
return;
}
// 表示用 → 内部用
const toInternal = (c) => {
if (c === "×") return "*";
if (c === "÷") return "/";
return c;
};
const last = toInternal(lastRaw);
// 内部用 → 表示用
const toDisplay = (c) => {
if (c === "*") return "×";
if (c === "/") return "÷";
return c;
};
const opForDisplay = toDisplay(op);
// 0 の時は - を符号として許可
if (display.value === "0" && op === "-") {
display.value = "-";
return;
}
if ("+-*/".includes(last)) {
// - を符号として許可するケース
if (op === "-" && last !== "-") {
display.value += "-";
return;
}
// 連続する演算子を整理
let trimmed = value;
while ("+-*/".includes(toInternal(trimmed.slice(-1)))) {
trimmed = trimmed.slice(0, -1);
}
display.value = trimmed + opForDisplay;
return;
}
display.value += opForDisplay;
}
連続演算子を整理する処理の中身 🔍
例えば、ユーザーが次のように入力したとします。
3 + - ×
内部では一度
"3+-×"
という文字列になります。
この状態では計算できないので、
末尾が演算子の間は1文字ずつ削除する 処理を行います。
while処理の流れ
1️⃣ "3+-×" → × 削除
2️⃣ "3+-" → - 削除
3️⃣ "3+" → + 削除
4️⃣ "3" → 数字なので終了
最終的に
display.value = "3×";
👉 計算可能な形だけを残す というわけです 👍
ここからが本題:- を符号か演算子か判定する 🧠
次は 「計算する直前」 の処理です。
① まずは式を分解する 🧩
const exprDisplay = display.value;
const exprForCalc = exprDisplay.replace(/×/g, "*").replace(/÷/g, "/");
let tokens = exprForCalc.match(/(\d+(?:\.\d+)?|[+\-*/])/g);
例
3 - 1 + 2 × -4 ÷ 2
👇 内部処理用に変換すると
tokens = ['3','-','1','+','2','*','-','4','/','2']
この時点では、- はすべて 演算子扱い です。
② - を符号か演算子か判定する関数 🧠
function mergeUnaryMinus(tokens) {
const result = [];
for (let i = 0; i < tokens.length; i++) {
const t = tokens[i];
const prev = result[result.length - 1];
const next = tokens[i + 1];
if (
t === "-" &&
next !== undefined &&
!isNaN(Number(next)) &&
(i === 0 || ["+", "-", "*", "/"].includes(prev))
) {
// 符号として扱う
result.push("-" + next);
i++;
} else {
result.push(t);
}
}
return result;
}
判定ルールを日本語で言うと ✍️
ー (マイナス) が 符号 になるのは次の条件すべてを満たすときです。
-
今見ているのが
ー -
次に数字がある かつ 式の先頭 または直前が演算子(+ - * /)
実際の処理結果 🔍
['3','-','1','+','2','*','-','4','/','2']
👇 mergeUnaryMinus 実行後
['3','-','1','+','2','*','-4','/','2']
👉 -4 が 1つの数値として扱える配列 になります 🎉
次回予告 🚀
次回はこの配列を使って
1️⃣ * / を優先して計算
2️⃣ 残った + - を左から計算
3️⃣ = を押したら結果を表示
という 本格的な計算処理 を実装していきます。
ここまでお読みいただきありがとうございました 🙇
「電卓ってこうやって作られてるんだ!」と感じてもらえたら嬉しいです!
