#javascript #reactjs #react-hooks #calculator
Вопрос:
Как следует из названия, я использую библиотеку математических выражений для выполнения своих вычислений, но у меня возникают проблемы с пониманием логики десятичных знаков и с тем, как предотвратить две десятичные дроби в одном числе внутри массива. я выделил ту часть, которая вызывает у меня проблемы. Вот ссылка на мою песочницу с кодом https://codesandbox.io/s/youthful-frost-2s6v6?file=/src/HookClaculator.js:181-2221
const [input, setInput] = useState([0]);
const [notANum, setNotANum] = useState("");
const [AC, setAC] = useState("");
const handleInputOneClick = (e) => {
let checkInput = input;
checkInput = [...checkInput, parseInt(e, 10)];
console.log(checkInput);
if (checkInput[1] !== 0) {
setInput([...input, parseInt(e, 10)]);
if (input.length > 23) {
console.log("exceeded 23");
setInput(["MAX DIGIT LIMIT REACHED"]);
setTimeout(() => {
setInput([0]);
}, 500);
}
}
};
const handleSymbolClick = (e) => {
if (Number.isInteger(input[input.length - 1])) {
setInput([...input, e]);
} else if (input[input.length - 1] === ".") {
setInput([...input, e]);
} else if (typeof input[input.length - 1] === "string") {
input.pop();
setInput([...input, e]);
}
};
const handleDecimalClick = (e) => {
if (input[input.length - 1] === ".") {
setInput([...input]);
} else if (isNaN(input[input.length - 1])) {
setInput([...input, e]);
} **else if (Number.isInteger(input[input.length - 1])) {
setInput([...input, e]);
}**
};
const handleEqualsClick = (e) => {
let exp = "";
if (input[0] === 0 amp;amp; input.length <= 1) {
console.log("hell yeah");
setNotANum(["NaN"]);
} else if (input.length > 1) {
console.log("input length is " input.length);
input.forEach((el) => {
return (exp = el);
});
let value = mexp.eval(exp);
setInput([value]);
}
};
const handleClickReset = (e) => {
setAC(e);
setInput([0]);
};
return (
<div id="calculator-div">
<HookDisplay input={input} notANum={notANum} AC={AC} />
<HookButtons
inputOneClick={handleInputOneClick}
symbolClick={handleSymbolClick}
decimalClick={handleDecimalClick}
handleEqualsButtonClick={handleEqualsClick}
handleClickReset={handleClickReset}
/>
</div>
);
};
return (
<div id="calculator-div">
<HookDisplay input={input} notANum={notANum} AC={AC} />
<HookButtons
inputOneClick={handleInputOneClick}
symbolClick={handleSymbolClick}
decimalClick={handleDecimalClick}
handleEqualsButtonClick={handleEqualsClick}
handleClickReset={handleClickReset}
/>
</div>
);
};
Ответ №1:
Я думаю, что прежде чем вводить десятичное число в массив, вы можете убедиться, что оно создаст допустимое выражение. Поскольку в настоящее время калькулятор поддерживает базовые операции, число никогда не может иметь более одного десятичного знака, а операндов может быть только на один больше, чем операторов, используя указанный факт. Это условие будет работать (внутри handleDecimalClick):
let lastIndex = -1;
for (let i = input.length - 1; i >= 0; i--) {
if (input[i] === ".") {
lastIndex = i;
} else if (
input[i] === " " ||
input[i] === "-" ||
input[i] === "*" ||
input[i] === "/"
) {
break;
}
}
if (lastIndex !== -1) return;
Кроме того, для дополнительной защиты добавлено регулярное выражение, чтобы проверить, является ли выражение допустимым, прежде чем оно отправится на оценку (добавлены нижеприведенные строки в уравнениях):
const inp = input.join("");
const regex = /(?:(?:^|[- _*/])(?:s*-?d (.d )?(?:[eE][ -]?d )?s*)) $/;
if (!regex.test(inp)) {
return;
}
Я разветвил ваш codesandbox и добавил исправление.