जावास्क्रिप्ट में गणितीय अभिव्यक्ति के रूप में एक स्ट्रिंग का मूल्यांकन


84

मैं अपनी संख्यात्मक मान प्राप्त '1+1'करने के eval(string)लिए कैसे एक स्ट्रिंग (जैसे ) में गणितीय अभिव्यक्ति का पार्स और मूल्यांकन करता हूं ?

उस उदाहरण के साथ, मैं चाहता हूं कि फ़ंक्शन स्वीकार करे '1+1'और वापस लौटे 2


5
बहुत समान है, लेकिन यह शायद आप जो चाह रहे हैं नहीं है: (Function("return 1+1;"))()
गुमबो

जवाबों:


73

आप जावास्क्रिप्ट अभिव्यक्ति इवैल्यूएटर लाइब्रेरी का उपयोग कर सकते हैं , जो आपको सामान करने की अनुमति देता है:

Parser.evaluate("2 ^ x", { x: 3 });

या मैथज , जो सामान की अनुमति देता है:

math.eval('sin(45 deg) ^ 2');

मैंने अपनी एक परियोजना के लिए मैथ्ज को चुनना समाप्त कर दिया।


23

आप आसानी से + या - कर सकते हैं:

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 को अधिक आकर्षक बनाता है- और निश्चित रूप से लिखने में सरल है।


2
+1 - संभवतः जो मैं साथ गया था, उससे थोड़ा अधिक सामान्य है, लेकिन यह मेरी स्थिति के लिए काम नहीं करेगा क्योंकि मेरे पास 1 + -2 जैसा कुछ हो सकता है, और मैं चाहता हूं कि अमान्य बयानों को भी हटा दें (मुझे लगता है कि आपकी अनुमति होगी) कुछ इस तरह "+ 3 + 4 +")
wheresrhys

मैंने छोटी नियमित अभिव्यक्ति के साथ एक अद्यतन उत्तर के नीचे पोस्ट किया है और ऑपरेटरों के बीच रिक्त स्थान की अनुमति देता है
स्टीफन गैबोस

17

किसी को उस तार को पार्स करना है। यदि यह दुभाषिया (के माध्यम से eval) नहीं है, तो यह आपको होने की आवश्यकता होगी, संख्याओं, ऑपरेटरों को निकालने के लिए एक पार्सिंग दिनचर्या लिखना, और कुछ भी जो आप गणितीय अभिव्यक्ति में समर्थन करना चाहते हैं।

तो, नहीं, बिना कोई (सरल) तरीका नहीं है eval। यदि आप सुरक्षा के बारे में चिंतित हैं (क्योंकि आप जिस इनपुट को पार्स कर रहे हैं वह आपके द्वारा नियंत्रित स्रोत से नहीं है), तो शायद आप इनपुट के प्रारूप (श्वेतसूची रेगेक्स फ़िल्टर के माध्यम से) को पास करने से पहले जांच सकते हैं eval?


1
यह सुरक्षा नहीं है जो मुझे परेशान करता है (मेरे पास पहले से ही नौकरी के लिए एक regexp है), यह ब्राउज़र पर अधिक लोड है क्योंकि मुझे इस तरह के बहुत सारे तार को संसाधित करना होगा। क्या एक कस्टम पार्सर संभवतया eval () से तेज हो सकता है?
wheresrhys

11
@wheresrhys: आप क्यों सोचेंगे कि आपका पार्सर, जेएस में लिखा गया है, सिस्टम द्वारा प्रदान की गई तुलना में तेज होने वाला है (अनुकूलित, शायद C या C ++ में लिखा गया है)?
एमएमएक्स

4
eval ऐसा करने का सबसे तेज़ तरीका है। हालाँकि, सुरक्षा सुनिश्चित करने के लिए एक regexp आमतौर पर पर्याप्त नहीं है।
लेविक

1
@wheresrhys: आपके पास इस तरह के बहुत सारे तार क्यों हैं? क्या वे एक कार्यक्रम द्वारा उत्पन्न हो रहे हैं? यदि हां, तो स्ट्रिंग्स में परिवर्तित होने से पहले परिणाम को गणना करना सबसे सरल तरीका है। अन्यथा, यह आपका खुद का-लिखने वाला समय है।
फिल एच

13

एक उत्कृष्ट नियमित अभिव्यक्ति और ऑपरेटरों के बीच रिक्त स्थान की अनुमति देकर @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);
        });
}

1
यह एकदम सही है, जब तक आपको केवल जोड़ और घटाव की आवश्यकता होती है। इतना कम कोड, इतना उत्पाद! निश्चिंत रहें, इसका इस्तेमाल अच्छे के लिए किया जा रहा है :)
अल्ट्रोमन द टॅक्मैन

10

मैंने इसी उद्देश्य के लिए BigEval बनाया ।
अभिव्यक्ति को हल करने में, यह बिल्कुल वैसा ही प्रदर्शन करता है Eval()और%, ^, &, ** (पावर) जैसे ऑपरेटरों का समर्थन करता है और! (भाज्य)। आपको अभिव्यक्ति के अंदर फ़ंक्शंस और कॉन्स्टेंट (या वैरिएबल) का उपयोग करने की अनुमति है। अभिव्यक्ति 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

यह अंकगणित के लिए उन बिग नंबर पुस्तकालयों का उपयोग करने के लिए भी किया जा सकता है जब आप मनमाने ढंग से सटीक संख्या के साथ काम कर रहे हैं।


8

मैं गणितीय अभिव्यक्तियों के मूल्यांकन के लिए जावास्क्रिप्ट पुस्तकालयों की तलाश में गया, और इन दो होनहार उम्मीदवारों को पाया:

  • जावास्क्रिप्ट अभिव्यक्ति का मूल्यांकन : छोटे और उम्मीद से अधिक हल्के वजन। बीजीय अभिव्यक्ति, प्रतिस्थापन और कई कार्यों की अनुमति देता है।

  • मैथज : जटिल संख्या, मैट्रिक्स और इकाइयों को भी अनुमति देता है। इन-ब्राउज़र जावास्क्रिप्ट और Node.js.


मैंने अब जावास्क्रिप्ट अभिव्यक्ति का मूल्यांकन किया है, और यह रॉक करने लगता है। (मैथ्ज शायद चट्टानें भी हैं, लेकिन यह मेरे उद्देश्यों के लिए थोड़ा बहुत बड़ा लगता है और मुझे जेएसईई में प्रतिस्थापन कार्यक्षमता भी पसंद है।)
इटंज़ालो

7

मैंने हाल ही Eval()में रिवर्स पोलिश नोटेशन (जो आसान बिट है) में अभिव्यक्ति का मूल्यांकन करके C # ( हमारे लिए नहीं ...) में यह किया है । कठिन हिस्सा वास्तव में स्ट्रिंग को पार्स कर रहा है और इसे रिवर्स पोलिश नोटेशन में बदल रहा है। मैंने शंटिंग यार्ड एल्गोरिदम का उपयोग किया , क्योंकि विकिपीडिया और छद्मकोड पर एक बढ़िया उदाहरण है। मुझे वास्तव में दोनों को लागू करना आसान लगा और मैं यह सलाह दूंगा कि अगर आपको पहले से कोई समाधान नहीं मिला है या विकल्प की तलाश है।


क्या आप विकिपीडिया पर कुछ उदाहरण या लिंक प्रदान कर सकते हैं?
LetynSOFT

@LetynSOFT स्यूडोकोड यहाँ
मेयोनेज़

6

यह एक छोटा सा फंक्शन है जिसे मैंने अभी इस मुद्दे को हल करने के लिए एक साथ फेंक दिया है - यह एक समय में स्ट्रिंग एक वर्ण का विश्लेषण करके अभिव्यक्ति का निर्माण करता है (यह वास्तव में बहुत जल्दी है हालांकि)। यह किसी भी गणितीय अभिव्यक्ति (केवल +, -, *, / ऑपरेटरों तक सीमित) और परिणाम लौटाएगा। यह नकारात्मक मान और असीमित संख्या के संचालन को भी संभाल सकता है।

केवल "करने के लिए" छोड़ दिया है यह सुनिश्चित करने के लिए कि यह * और / से पहले और - की गणना करता है। बाद में उस कार्यक्षमता को जोड़ देगा, लेकिन अब के लिए यह वही है जो मुझे चाहिए ...

/**
* 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;
}

4

सरल और साथ सुरुचिपूर्ण Function()

function parse(str) {
  return Function(`'use strict'; return (${str})`)()
}

parse("1+2+3"); 


क्या आप बता सकते हैं कि यह कैसे काम करता है? मैं इस वाक्यविन्यास के लिए नया हूँ
पेजनॉटफॉन्ड 14

समारोह ("वापसी (1 + 2 + 3)") (); - इसका एक अनाम कार्य है। हम सिर्फ तर्क (फंक्शन बॉडी) पर अमल कर रहे हैं। समारोह ("{वापसी (1 + 2 + 3)}") ();
अनिकेत कुदले

ठीक है कैसे स्ट्रिंग पार्स है? और वह ($ {str}) ) -----क्या है?
पेजनोटफाइंड

मैं नहीं देखता कि यह कैसे किसी भी तरह से बेहतर है। इस सर्वर-साइड को चलाने से पहले, सावधान रहें parse('process.exit()')
बस्ती

3

आप यह जांचने के लिए लूप का उपयोग कर सकते हैं कि क्या स्ट्रिंग में कोई अमान्य वर्ण हैं और फिर एक प्रयास का उपयोग करें ... यदि कोई गणना त्रुटि की तरह फेंकता है, तो इसे जांचने के लिए 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'))


2

मैं आखिरकार इस समाधान के लिए गया हूं, जो सकारात्मक और नकारात्मक पूर्णांक के योग के लिए काम करता है (और रेगेक्स के लिए थोड़ा संशोधन के साथ दशमलव भी काम करेगा):

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 () की तुलना में तेज़ है, लेकिन जैसा कि मुझे कई बार ऑपरेशन करना पड़ता है, मैं इस स्क्रिप्ट को जावास्क्रिप्ट कंपाइलर के इंस्टेंस के भार को बनाने की तुलना में कहीं अधिक आरामदायक हूं।


1
हालांकि returnएक अभिव्यक्ति के अंदर इस्तेमाल नहीं किया जा सकता है, NaNsum("+1") लौटाता है ।
गुम्बो

हमेशा फोरगेट करें कि वापसी के लिए या एक टर्नरी अभिव्यक्ति के अंदर नहीं जा सकता है। मैं "+1" को बाहर करना चाहूंगा क्योंकि यद्यपि यह एक संख्या के रूप में 'मूल्यांकन' करना चाहिए, यह वास्तव में रोजमर्रा के अर्थ में गणितीय योग का उदाहरण नहीं है। मेरा कोड स्वीकार्य स्ट्रिंग्स के लिए मूल्यांकन और फ़िल्टर दोनों के लिए डिज़ाइन किया गया है।
व्हाट्सएप करें


2

मेरा मानना ​​है कि parseIntऔर इस स्थिति में ईएस 6 मददगार हो सकता है

let func = (str) => {
  let arr = str.split("");
  return `${Number(arr[0]) + parseInt(arr[1] + Number(arr[2]))}`
};

console.log(func("1+1"));

यहां मुख्य बात यह है कि parseIntऑपरेटर के साथ संख्या को पार्स करता है। कोड को संगत जरूरतों के लिए संशोधित किया जा सकता है।


1

AutoCalculator आज़माएं https://github.com/JavscriptLab/autocalculate इनपुट्स मूल्य और आउटपुट का चयन चयनकर्ता के भाव से करें

बस अपने आउटपुट इनपुट के लिए एक विशेषता जोड़ें जैसे डेटा-एसी = "(# firstinput + # secondinput)"

किसी भी आरंभीकरण की कोई आवश्यकता नहीं है केवल डेटा-एसी विशेषता जोड़ें। यह स्वचालित रूप से गतिशील रूप से जोड़े गए तत्वों का पता लगाएगा

आउटपुट के साथ 'रु' जोड़ने के लिए घुंघराले ब्रैकेट डेटा-एसी = "{रु}" (# फर्स्टपिन + # सेकेंडपुट) के साथ जोड़ें


1
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

1
घटाव, गुणा और भाग के बारे में क्या? num1 से गुणा क्यों करें ?
नथनफ्राँके

इसे इंगित करने के लिए धन्यवाद @nathanfranke मैंने इसे और अधिक सामान्य बनाने के लिए उत्तर को अपडेट किया है। अब यह सभी 4 ऑपरेशन का समर्थन करता है। और 1 से कई इसे स्ट्रिंग से संख्या में बदलना था। जिसे हम + num करके भी प्राप्त कर सकते हैं।
रुशिकेश भार

0

यहाँ jMichael के समान एक एल्गोरिदमिक सॉल्यूशन दिया गया है जो कि वर्ण द्वारा अभिव्यक्ति चरित्र के माध्यम से लूप करता है और उत्तरोत्तर बाएँ / ऑपरेटर / दाएं को ट्रैक करता है। यह फ़ंक्शन प्रत्येक संचालक चरित्र को खोजने के बाद परिणाम को जमा करता है। यह संस्करण केवल '+' और '-' ऑपरेटरों का समर्थन करता है, लेकिन अन्य ऑपरेटरों के साथ विस्तारित होने के लिए लिखा जाता है। नोट: हम लूपिंग से पहले 'कराप' को '+' पर सेट करते हैं क्योंकि हम मानते हैं कि अभिव्यक्ति एक सकारात्मक फ्लोट से शुरू होती है। वास्तव में, कुल मिलाकर मैं यह धारणा बना रहा हूं कि इनपुट एक कैलकुलेटर से क्या होगा।

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);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.