숫자 값을 생성하기 위해 '1+1'호출하지 않고 문자열 (예 :)에서 수학 표현식을 구문 분석하고 평가하는 방법은 eval(string)무엇입니까?
이 예제에서는 함수가을 받아들이고 '1+1'반환 하기를 원합니다 2.
답변:
다음 과 같은 작업을 수행 할 수있는 JavaScript Expression Evaluator 라이브러리 를 사용할 수 있습니다.
Parser.evaluate("2 ^ x", { x: 3 });
math.eval('sin(45 deg) ^ 2');
결국 내 프로젝트 중 하나에 mathjs를 선택했습니다.
+ 또는-를 쉽게 수행 할 수 있습니다.
function addbits(s) {
var total = 0,
s = s.match(/[+\-]*(\.\d+|\d+(\.\d+)?)/g) || [];
while (s.length) {
total += parseFloat(s.shift());
}
return total;
}
var string = '1+23+4+5-30';
console.log(
addbits(string)
)
더 복잡한 수학은 eval을 더 매력적으로 만들고 확실히 쓰기를 더 간단하게 만듭니다.
누군가 그 문자열을 파싱해야합니다. 인터프리터가 아니라면 (을 통해 eval) 숫자, 연산자 및 수학 표현식에서 지원하려는 다른 모든 것을 추출하는 구문 분석 루틴을 작성하는 것이 당신이어야합니다.
따라서 .NET 없이는 (간단한) 방법이 없습니다 eval. 보안에 대해 우려하는 경우 (파싱하는 입력이 제어하는 소스가 아니기 때문에) eval?에 전달하기 전에 입력의 형식 (화이트리스트 정규식 필터를 통해)을 확인할 수 있습니다 .
더 짧은 정규 표현식을 사용하고 연산자 사이에 공백을 허용하는 @kennebec의 우수한 답변에 대한 대안
function addbits(s) {
var total = 0;
s = s.replace(/\s/g, '').match(/[+\-]?([0-9\.\s]+)/g) || [];
while(s.length) total += parseFloat(s.shift());
return total;
}
그것을 사용하십시오
addbits('5 + 30 - 25.1 + 11');
최신 정보
더 최적화 된 버전이 있습니다.
function addbits(s) {
return (s.replace(/\s/g, '').match(/[+\-]?([0-9\.]+)/g) || [])
.reduce(function(sum, value) {
return parseFloat(sum) + parseFloat(value);
});
}
같은 목적으로 BigEval 을 만들었습니다 .
식을 풀 때 Eval()%, ^, &, ** (승수) 및! (계승). 표현식 내에서 함수와 상수 (또는 변수)를 사용할 수도 있습니다. 표현식은 JavaScript를 포함한 프로그래밍 언어에서 일반적으로 사용되는 PEMDAS 순서 로 해결됩니다 .
var Obj = new BigEval();
var result = Obj.exec("5! + 6.6e3 * (PI + E)"); // 38795.17158152233
var result2 = Obj.exec("sin(45 * deg)**2 + cos(pi / 4)**2"); // 1
var result3 = Obj.exec("0 & -7 ^ -7 - 0%1 + 6%2"); //-7
임의의 정밀도로 숫자를 처리하는 경우 산술에 해당 Big Number 라이브러리를 사용하도록 만들 수도 있습니다.
수학적 표현을 평가하기 위해 JavaScript 라이브러리를 찾고 있었고 다음 두 가지 유망한 후보를 찾았습니다.
JavaScript Expression Evaluator : 더 작고 가볍습니다. 대수식, 대체 및 여러 함수를 허용합니다.
mathjs : 복소수, 행렬 및 단위도 허용합니다. 브라우저 내 JavaScript 및 Node.js 모두에서 사용하도록 제작되었습니다.
저는 최근 Eval()에 Reverse Polish Notation 의 표현을 평가하여 C #에서이 작업을 수행했습니다 ( 우리에게는 아닙니다 ... ). 어려운 부분은 실제로 문자열을 구문 분석하여 Reverse Polish Notation으로 바꾸는 것입니다. Wikipedia 및 의사 코드에 대한 훌륭한 예가 있으므로 Shunting Yard 알고리즘을 사용했습니다 . 둘 다 구현하는 것이 정말 간단하다는 것을 알았고 아직 해결책을 찾지 못했거나 대안을 찾고 있다면 이것을 권장합니다.
이것은이 문제를 해결하기 위해 방금 모아 놓은 작은 함수입니다. 한 번에 한 문자 씩 문자열을 분석하여 표현식을 작성합니다 (실제로는 꽤 빠릅니다). 이것은 모든 수학 식 (+,-, *, / 연산자로만 제한됨)을 취하고 결과를 반환합니다. 음수 값과 무제한 숫자 연산도 처리 할 수 있습니다.
남은 유일한 "해야 할 일"은 + &-전에 * & /를 계산하는 것입니다. 나중에 해당 기능을 추가 할 예정이지만 지금은 필요한 작업을 수행합니다.
/**
* Evaluate a mathematical expression (as a string) and return the result
* @param {String} expr A mathematical expression
* @returns {Decimal} Result of the mathematical expression
* @example
* // Returns -81.4600
* expr("10.04+9.5-1+-100");
*/
function expr (expr) {
var chars = expr.split("");
var n = [], op = [], index = 0, oplast = true;
n[index] = "";
// Parse the expression
for (var c = 0; c < chars.length; c++) {
if (isNaN(parseInt(chars[c])) && chars[c] !== "." && !oplast) {
op[index] = chars[c];
index++;
n[index] = "";
oplast = true;
} else {
n[index] += chars[c];
oplast = false;
}
}
// Calculate the expression
expr = parseFloat(n[0]);
for (var o = 0; o < op.length; o++) {
var num = parseFloat(n[o + 1]);
switch (op[o]) {
case "+":
expr = expr + num;
break;
case "-":
expr = expr - num;
break;
case "*":
expr = expr * num;
break;
case "/":
expr = expr / num;
break;
}
}
return expr;
}
간단하고 우아한 Function()
function parse(str) {
return Function(`'use strict'; return (${str})`)()
}
parse("1+2+3");
) -----()`마지막으로이 대괄호?
parse('process.exit()').
for 루프를 사용하여 문자열에 잘못된 문자가 포함되어 있는지 확인한 다음 eval과 함께 try ... catch를 사용하여 계산에서 원하는 오류가 발생하는지 확인할 eval("2++")수 있습니다.
function evaluateMath(str) {
for (var i = 0; i < str.length; i++) {
if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) {
return NaN;
}
}
try {
return eval(str)
} catch (e) {
if (e.name !== 'SyntaxError') throw e
return NaN;
}
}
console.log(evaluateMath('2 + 6'))
또는 함수 대신 설정할 수 있습니다. Math.eval
Math.eval = function(str) {
for (var i = 0; i < str.length; i++) {
if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) {
return NaN;
}
}
try {
return eval(str)
} catch (e) {
if (e.name !== 'SyntaxError') throw e
return NaN;
}
}
console.log(Math.eval('2 + 6'))
결국 양수와 음수를 합산하는이 솔루션을 사용했습니다 (정규식을 약간 수정하면 십진수에서도 작동합니다).
function sum(string) {
return (string.match(/^(-?\d+)(\+-?\d+)*$/)) ? string.split('+').stringSum() : NaN;
}
Array.prototype.stringSum = function() {
var sum = 0;
for(var k=0, kl=this.length;k<kl;k++)
{
sum += +this[k];
}
return sum;
}
eval ()보다 빠른지 확실하지 않지만 작업을 여러 번 수행해야하므로 자바 스크립트 컴파일러의 인스턴스를 생성하는 것보다이 스크립트를 실행하는 것이 훨씬 더 편합니다.
return표현의 내부에 사용할 수 없습니다, sum("+1")반환 NaN이를 .
AutoCalculator https://github.com/JavscriptLab/autocalculate Calculate Inputs value and Output By using selector expressions
data-ac = "(# firstinput + # secondinput)"과 같은 출력 입력에 속성을 추가하기 만하면됩니다.
초기화 할 필요가 없습니다. data-ac 속성 만 추가하면됩니다. 동적으로 추가 된 요소를 자동으로 찾습니다.
또는 출력에 'Rs'를 추가하려면 중괄호 안에 추가하십시오. data-ac = "{Rs} (# firstinput + # secondinput)"
const operatorToFunction = {
"+": (num1, num2) => +num1 + +num2,
"-": (num1, num2) => +num1 - +num2,
"*": (num1, num2) => +num1 * +num2,
"/": (num1, num2) => +num1 / +num2
}
const findOperator = (str) => {
const [operator] = str.split("").filter((ch) => ["+", "-", "*", "/"].includes(ch))
return operator;
}
const executeOperation = (str) => {
const operationStr = str.replace(/[ ]/g, "");
const operator = findOperator(operationStr);
const [num1, num2] = operationStr.split(operator)
return operatorToFunction[operator](num1, num2);
};
const addition = executeOperation('1 + 1'); // ans is 2
const subtraction = executeOperation('4 - 1'); // ans is 3
const multiplication = executeOperation('2 * 5'); // ans is 10
const division = executeOperation('16 / 4'); // ans is 4
num1을 곱 해야합니까?
다음은 문자별로 표현 문자를 반복하고 왼쪽 / 연산자 / 오른쪽을 점진적으로 추적하는 jMichael과 유사한 알고리즘 솔루션입니다. 이 함수는 회전 할 때마다 연산자 문자를 찾은 후 결과를 누적합니다. 이 버전은 '+'및 '-'연산자 만 지원하지만 다른 연산자로 확장되도록 작성되었습니다. 참고 : 표현식이 양의 부동 소수점으로 시작한다고 가정하기 때문에 루프 전에 'currOp'를 '+'로 설정합니다. 사실 전반적으로 저는 입력이 계산기에서 나오는 것과 비슷하다고 가정하고 있습니다.
function calculate(exp) {
const opMap = {
'+': (a, b) => { return parseFloat(a) + parseFloat(b) },
'-': (a, b) => { return parseFloat(a) - parseFloat(b) },
};
const opList = Object.keys(opMap);
let acc = 0;
let next = '';
let currOp = '+';
for (let char of exp) {
if (opList.includes(char)) {
acc = opMap[currOp](acc, next);
currOp = char;
next = '';
} else {
next += char;
}
}
return currOp === '+' ? acc + parseFloat(next) : acc - parseFloat(next);
}
(Function("return 1+1;"))().