数値を生成するために'1+1'
呼び出すことなく、文字列(たとえば)の数式を解析および評価するにはどうすればよいeval(string)
ですか?
その例では、関数がを受け入れ'1+1'
て返すようにし2
ます。
数値を生成するために'1+1'
呼び出すことなく、文字列(たとえば)の数式を解析および評価するにはどうすればよいeval(string)
ですか?
その例では、関数がを受け入れ'1+1'
て返すようにし2
ます。
回答:
あなたは使用することができますJavaScript式エバリュエータライブラリあなたはのようなものを行うことができます:
Parser.evaluate("2 ^ x", { x: 3 });
または、次のようなものを許可するmathjs:
math.eval('sin(45 deg) ^ 2');
私は自分のプロジェクトの1つに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
)インタプリタでない場合は、数値、演算子、および数式でサポートしたいその他のものを抽出するための解析ルーチンを作成する、あなたである必要があります。
したがって、いいえ、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
任意の精度で数値を処理する場合は、これらのBigNumberライブラリを算術演算に使用することもできます。
数式を評価するためのJavaScriptライブラリを探しに行ったところ、次の2つの有望な候補が見つかりました。
JavaScript式エバリュエーター:より小さく、できればより軽量になります。代数式、置換、およびいくつかの関数を許可します。
mathjs:複素数、行列、単位も使用できます。ブラウザ内のJavaScriptとNode.jsの両方で使用するように構築されています。
これは、この問題を解決するために今一緒に作成した小さな関数です。文字列を一度に1文字ずつ分析して式を作成します(実際にはかなり高速です)。これは任意の数式(+、-、*、/演算子のみに限定)を取り、結果を返します。負の値や無制限の数の演算も処理できます。
残っている唯一の「やるべきこと」は、+&-の前に*&/を計算することを確認することです。後でその機能を追加しますが、今のところこれは私が必要なことをします...
/**
* 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");
) -----
ですか($ {str})() `ついにこの括弧?
parse('process.exit()')
。
forループを使用して文字列に無効な文字が含まれているかどうかを確認してから、try ... catchとevalを使用して、計算でエラーがスローされるかどうかを確認できます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()よりも高速かどうかはわかりませんが、操作を何度も実行する必要があるため、javascriptコンパイラのインスタンスを大量に作成するよりもこのスクリプトを実行する方がはるかに快適です。
return
表現内で使用することができない、sum("+1")
返しNaNが。
AutoCalculatorを試してください https://github.com/JavscriptLab/autocalculate セレクター式を使用して入力値と出力を計算します
data-ac = "(#firstinput +#secondinput)"のような出力入力の属性を追加するだけです
初期化の必要はありません。data-ac属性のみを追加するだけです。動的に追加された要素を自動的に検出します
または、出力で「Rs」を追加するだけで、中括弧内にデータを追加します-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
num
1を掛けるのですか?
これは、jMichaelと同様のアルゴリズムソリューションであり、式を1文字ずつループし、左/演算子/右を段階的に追跡します。この関数は、各ターン後にオペレーター文字を見つけた後に結果を累積します。このバージョンは「+」および「-」演算子のみをサポートしますが、他の演算子で拡張するように記述されています。注:式は正のfloatで始まると想定しているため、ループする前に「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;"))()
。