मैं String
मूल्यों से सरल गणित के भावों का मूल्यांकन करने के लिए एक जावा रूटीन लिखने की कोशिश कर रहा हूं :
"5+3"
"10-40"
"10*3"
मैं बहुत सारे इफ-तत्कालीन बयानों से बचना चाहता हूं। मैं यह कैसे कर सकता हूँ?
मैं String
मूल्यों से सरल गणित के भावों का मूल्यांकन करने के लिए एक जावा रूटीन लिखने की कोशिश कर रहा हूं :
"5+3"
"10-40"
"10*3"
मैं बहुत सारे इफ-तत्कालीन बयानों से बचना चाहता हूं। मैं यह कैसे कर सकता हूँ?
जवाबों:
JDK1.6 के साथ, आप अंतर्निहित जावास्क्रिप्ट इंजन का उपयोग कर सकते हैं।
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
public class Test {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = "40+2";
System.out.println(engine.eval(foo));
}
}
return (Double) engine.eval(foo);
new javax.script.ScriptEngineManager().getEngineByName("JavaScript") .eval("var f = new java.io.FileWriter('hello.txt'); f.write('UNLIMITED POWER!'); f.close();");
- जावास्क्रिप्ट के माध्यम से एक फ़ाइल लिखेंगे (डिफ़ॉल्ट रूप से) कार्यक्रम की वर्तमान निर्देशिका
मैंने eval
इस प्रश्न का उत्तर देने के लिए अंकगणितीय अभिव्यक्तियों के लिए यह विधि लिखी है । यह जोड़, घटाव, गुणा, भाग, घातांक ( ^
प्रतीक का उपयोग ), और कुछ बुनियादी कार्य करता है sqrt
। यह (
... का उपयोग कर समूहीकरण का समर्थन करता है )
, और यह ऑपरेटर की पूर्ववर्तीता और सहानुभूति नियमों को सही करता है।
public static double eval(final String str) {
return new Object() {
int pos = -1, ch;
void nextChar() {
ch = (++pos < str.length()) ? str.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') nextChar();
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
return x;
}
// Grammar:
// expression = term | expression `+` term | expression `-` term
// term = factor | term `*` factor | term `/` factor
// factor = `+` factor | `-` factor | `(` expression `)`
// | number | functionName factor | factor `^` factor
double parseExpression() {
double x = parseTerm();
for (;;) {
if (eat('+')) x += parseTerm(); // addition
else if (eat('-')) x -= parseTerm(); // subtraction
else return x;
}
}
double parseTerm() {
double x = parseFactor();
for (;;) {
if (eat('*')) x *= parseFactor(); // multiplication
else if (eat('/')) x /= parseFactor(); // division
else return x;
}
}
double parseFactor() {
if (eat('+')) return parseFactor(); // unary plus
if (eat('-')) return -parseFactor(); // unary minus
double x;
int startPos = this.pos;
if (eat('(')) { // parentheses
x = parseExpression();
eat(')');
} else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
x = Double.parseDouble(str.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') { // functions
while (ch >= 'a' && ch <= 'z') nextChar();
String func = str.substring(startPos, this.pos);
x = parseFactor();
if (func.equals("sqrt")) x = Math.sqrt(x);
else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
else throw new RuntimeException("Unknown function: " + func);
} else {
throw new RuntimeException("Unexpected: " + (char)ch);
}
if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation
return x;
}
}.parse();
}
उदाहरण:
System.out.println(eval("((4 - 2^3 + 1) * -sqrt(3*3+4*4)) / 2"));
आउटपुट: 7.5 (जो सही है)
पार्सर एक पुनरावर्ती वंशीय पार्सर है , इसलिए आंतरिक रूप से इसके व्याकरण में ऑपरेटर स्तर की पूर्वता के प्रत्येक स्तर के लिए अलग-अलग पार्स तरीकों का उपयोग करता है। मैंने इसे छोटा रखा है इसलिए इसे संशोधित करना आसान है, लेकिन यहां कुछ विचार दिए गए हैं जिन्हें आप इसके साथ विस्तारित करना चाहते हैं:
चर:
Parser की बिट्स जो फ़ंक्शन के लिए नामों को पढ़ती है, आसानी से कस्टम चर को संभालने के लिए आसानी से बदली जा सकती है, eval
विधि में पारित चर तालिका में नामों को देखकर , जैसे कि a Map<String,Double> variables
।
अलग संकलन और मूल्यांकन:
क्या हो सकता है, अगर चर के लिए समर्थन जोड़ा जा रहा है, तो आप हर बार पार्स किए बिना, उसी परिवर्तन का मूल्यांकन लाखों परिवर्तित चर के साथ करना चाहते हैं? यह संभव है। पहले से परिभाषित अभिव्यक्ति का मूल्यांकन करने के लिए उपयोग करने के लिए एक इंटरफ़ेस परिभाषित करें:
@FunctionalInterface
interface Expression {
double eval();
}
अब सभी तरीकों को बदलें जो double
एस वापस करते हैं , इसलिए इसके बजाय वे उस इंटरफ़ेस का एक उदाहरण देते हैं। जावा 8 का लैम्ब्डा सिंटेक्स इसके लिए बहुत अच्छा काम करता है। परिवर्तित तरीकों में से एक का उदाहरण:
Expression parseExpression() {
Expression x = parseTerm();
for (;;) {
if (eat('+')) { // addition
Expression a = x, b = parseTerm();
x = (() -> a.eval() + b.eval());
} else if (eat('-')) { // subtraction
Expression a = x, b = parseTerm();
x = (() -> a.eval() - b.eval());
} else {
return x;
}
}
}
यह Expression
संकलित अभिव्यक्ति (एक सार वाक्यविन्यास वृक्ष ) का प्रतिनिधित्व करने वाली वस्तुओं का एक पुनरावर्ती पेड़ बनाता है । फिर आप इसे एक बार संकलित कर सकते हैं और विभिन्न मूल्यों के साथ इसका बार-बार मूल्यांकन कर सकते हैं:
public static void main(String[] args) {
Map<String,Double> variables = new HashMap<>();
Expression exp = parse("x^2 - x + 2", variables);
for (double x = -20; x <= +20; x++) {
variables.put("x", x);
System.out.println(x + " => " + exp.eval());
}
}
विभिन्न डेटाटाइप्स:
इसके बजाय double
, आप मूल्यांकनकर्ता को कुछ अधिक शक्तिशाली उपयोग करने के लिए बदल सकते हैं जैसे BigDecimal
, या एक वर्ग जो जटिल संख्याओं, या तर्कसंगत संख्याओं (अंशों) को लागू करता है। तुम भी उपयोग कर सकते हैं Object
, कुछ वास्तविक प्रोग्रामिंग भाषा की तरह, भावप्रवणता के कुछ मिश्रण की अनुमति। :)
इस जवाब जारी किया गया के सभी कोड सार्वजनिक क्षेत्र के लिए । मज़े करो!
double x = parseTerm();
ऑपरेटर for (;;) {...}
स्तर (इसके अलावा, घटाव) के आत्मघाती संचालन का मूल्यांकन करने के बाद, बाएं ऑपरेटर का मूल्यांकन करें । एक ही तर्क हैं और पार्सटर्म विधि में। ParseFactor का अगला स्तर नहीं होता है, इसलिए केवल विधियों / चर का मूल्यांकन होता है या पार्थिनेसिस के मामले में - उप-अभिव्यक्ति का मूल्यांकन करते हैं। boolean eat(int charToEat)
CharToEat चरित्र के साथ वर्तमान कर्सर चरित्र की विधि की जांच समानता, अगर अगले वर्ण के बराबर वापसी सच और कदम कर्सर, मैं नाम का उपयोग इसके लिए 'स्वीकार'।
इसे हल करने का सही तरीका एक लेसर और एक पार्सर के साथ है । आप इनमें से सरल संस्करण स्वयं लिख सकते हैं, या उन पृष्ठों में जावा लेकर्स और पार्सर्स के लिंक भी हैं।
एक पुनरावर्ती वंशीय पार्सर बनाना वास्तव में अच्छा सीखने का व्यायाम है।
मेरे विश्वविद्यालय के प्रोजेक्ट के लिए, मैं दोनों मूल फ़ार्मुलों और अधिक जटिल समीकरणों (विशेष रूप से पुनरावृत्त ऑपरेटरों) का समर्थन करने वाले पार्सर / मूल्यांकनकर्ता की तलाश कर रहा था। मुझे JAVA और .NET के लिए बहुत अच्छा खुला स्रोत पुस्तकालय मिला, जिसे mXparser कहा जाता है। मैं सिंटैक्स पर कुछ महसूस करने के लिए कुछ उदाहरण दूंगा, आगे के निर्देशों के लिए कृपया प्रोजेक्ट वेबसाइट (विशेषकर ट्यूटोरियल अनुभाग) पर जाएं।
https://mathparser.org/mxparser-tutorial/
और कुछ उदाहरण
1 - सरल फरमुला
Expression e = new Expression("( 2 + 3/4 + sin(pi) )/2");
double v = e.calculate()
2 - उपयोगकर्ता परिभाषित तर्क और स्थिरांक
Argument x = new Argument("x = 10");
Constant a = new Constant("a = pi^2");
Expression e = new Expression("cos(a*x)", x, a);
double v = e.calculate()
3 - उपयोगकर्ता परिभाषित कार्य
Function f = new Function("f(x, y, z) = sin(x) + cos(y*z)");
Expression e = new Expression("f(3,2,5)", f);
double v = e.calculate()
4 - गर्भाधान
Expression e = new Expression("sum( i, 1, 100, sin(i) )");
double v = e.calculate()
हाल ही में मिला - यदि आप वाक्यविन्यास को आज़माना चाहते हैं (और उन्नत उपयोग के मामले को देखें) तो आप स्केलर कैलकुलेटर ऐप डाउनलोड कर सकते हैं जो mXparser द्वारा संचालित है।
सादर
यहाँ GitHub पर एक और ओपन सोर्स लाइब्रेरी है जिसका नाम EvalEx है।
जावास्क्रिप्ट इंजन के विपरीत यह पुस्तकालय केवल गणितीय अभिव्यक्तियों के मूल्यांकन में केंद्रित है। इसके अलावा, पुस्तकालय विस्तार योग्य है और बूलियन ऑपरेटरों के साथ-साथ कोष्ठक के उपयोग का समर्थन करता है।
आप बीनशेल दुभाषिया भी आज़मा सकते हैं :
Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));
आप आसानी से भावों का मूल्यांकन कर सकते हैं यदि आपका जावा एप्लिकेशन पहले से ही किसी अन्य JAR का उपयोग किए बिना, डेटाबेस तक पहुंचता है।
कुछ डेटाबेस के लिए आपको डमी टेबल (उदाहरण के लिए, ओरेकल की "दोहरी" तालिका) का उपयोग करने की आवश्यकता होती है और अन्य आपको किसी भी तालिका से "चयन" किए बिना अभिव्यक्ति का मूल्यांकन करने की अनुमति देंगे।
उदाहरण के लिए, Sql Server या Sqlite में
select (((12.10 +12.0))/ 233.0) amount
और ओरेकल में
select (((12.10 +12.0))/ 233.0) amount from dual;
DB का उपयोग करने का लाभ यह है कि आप एक ही समय में कई अभिव्यक्तियों का मूल्यांकन कर सकते हैं। इसके अलावा अधिकांश डीबी आपको अत्यधिक जटिल अभिव्यक्तियों का उपयोग करने की अनुमति देगा और इसमें कई अतिरिक्त कार्य भी होंगे जिन्हें आवश्यक कहा जा सकता है।
हालाँकि, कई एकल अभिव्यक्तियों का व्यक्तिगत रूप से मूल्यांकन करने की आवश्यकता होती है, खासकर जब DB एक नेटवर्क सर्वर पर स्थित होता है, तो प्रदर्शन को नुकसान हो सकता है।
निम्नलिखित एक Sqlite-in-memory डेटाबेस का उपयोग करके प्रदर्शन समस्या को कुछ हद तक संबोधित करता है।
यहाँ जावा में एक पूर्ण काम करने का उदाहरण दिया गया है
Class. forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount");
rs.next();
System.out.println(rs.getBigDecimal(1));
stat.close();
conn.close();
बेशक आप एक ही समय में कई गणनाओं को संभालने के लिए उपरोक्त कोड का विस्तार कर सकते हैं।
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount, (1+100)/20.0 amount2");
यह लेख विभिन्न दृष्टिकोणों पर चर्चा करता है। यहाँ लेख में उल्लिखित 2 मुख्य दृष्टिकोण दिए गए हैं:
स्क्रिप्ट के लिए अनुमति देता है कि जावा वस्तुओं के संदर्भ शामिल हैं।
// Create or retrieve a JexlEngine
JexlEngine jexl = new JexlEngine();
// Create an expression object
String jexlExp = "foo.innerFoo.bar()";
Expression e = jexl.createExpression( jexlExp );
// Create a context and add data
JexlContext jctx = new MapContext();
jctx.set("foo", new Foo() );
// Now evaluate the expression, getting the result
Object o = e.evaluate(jctx);
private static void jsEvalWithVariable()
{
List<String> namesList = new ArrayList<String>();
namesList.add("Jill");
namesList.add("Bob");
namesList.add("Laureen");
namesList.add("Ed");
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
jsEngine.put("namesListKey", namesList);
System.out.println("Executing in script environment...");
try
{
jsEngine.eval("var x;" +
"var names = namesListKey.toArray();" +
"for(x in names) {" +
" println(names[x]);" +
"}" +
"namesListKey.add(\"Dana\");");
}
catch (ScriptException ex)
{
ex.printStackTrace();
}
}
दूसरा तरीका स्प्रिंग एक्सप्रेशन लैंग्वेज या स्पेल का उपयोग करना है जो गणितीय अभिव्यक्तियों के मूल्यांकन के साथ-साथ पूरी तरह से बहुत कुछ करता है इसलिए शायद थोड़ा अधिक हो जाए। इस अभिव्यक्ति पुस्तकालय का उपयोग करने के लिए आपको स्प्रिंग फ्रेमवर्क का उपयोग करने की आवश्यकता नहीं है क्योंकि यह स्टैंड-अलोन है। स्पेल के प्रलेखन से उदाहरणों की नकल करना:
ExpressionParser parser = new SpelExpressionParser();
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); //24.0
अगर हम इसे लागू करने जा रहे हैं तो हम नीचे दिए गए एल्गोरिदम का उपयोग कर सकते हैं: -
जबकि अभी भी पढ़ने के लिए टोकन हैं,
१.१ अगला टोकन प्राप्त करें। 1.2 यदि टोकन है:
1.2.1 एक संख्या: इसे स्टैक मान पर रखें।
१.२.२ एक चर: इसका मान प्राप्त करें, और मूल्य स्टैक पर धकेलें।
1.2.3 एक बाईं कोष्ठक: इसे ऑपरेटर स्टैक पर धक्का दें।
1.2.4 एक सही कोष्ठक:
1 While the thing on top of the operator stack is not a
left parenthesis,
1 Pop the operator from the operator stack.
2 Pop the value stack twice, getting two operands.
3 Apply the operator to the operands, in the correct order.
4 Push the result onto the value stack.
2 Pop the left parenthesis from the operator stack, and discard it.
1.2.5 एक ऑपरेटर (इसे इसे कॉल करें):
1 While the operator stack is not empty, and the top thing on the
operator stack has the same or greater precedence as thisOp,
1 Pop the operator from the operator stack.
2 Pop the value stack twice, getting two operands.
3 Apply the operator to the operands, in the correct order.
4 Push the result onto the value stack.
2 Push thisOp onto the operator stack.
जबकि ऑपरेटर स्टैक खाली नहीं है, 1 ऑपरेटर स्टैक से ऑपरेटर को पॉप करें। 2 दो ऑपरेंड हो रही वैल्यू स्टैक को दो बार पॉप करें। 3 ऑपरेटर को ऑपरेंड में, सही क्रम में लागू करें। 4 परिणाम स्टैक पर परिणाम पुश करें।
इस बिंदु पर ऑपरेटर स्टैक खाली होना चाहिए, और मान स्टैक में केवल एक मान होना चाहिए, जो अंतिम परिणाम है।
यह एक और दिलचस्प विकल्प है https://github.com/Shy-Ta/expression-evaluator-demo
उपयोग बहुत सरल है और काम पूरा हो जाता है, उदाहरण के लिए:
ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");
assertEquals(BigDecimal.valueOf(11), evalExpr.eval());
मुझे लगता है कि आप कभी भी ऐसा करते हैं, इसमें बहुत सारे सशर्त बयान शामिल होते हैं। लेकिन अपने उदाहरणों की तरह एकल संचालन के लिए आप इसे 4 तक सीमित कर सकते हैं यदि कुछ के साथ कथन
String math = "1+4";
if (math.split("+").length == 2) {
//do calculation
} else if (math.split("-").length == 2) {
//do calculation
} ...
जब आप "4 + 5 * 6" जैसे कई कार्यों से निपटना चाहते हैं तो यह बहुत अधिक जटिल हो जाता है।
यदि आप एक कैलकुलेटर बनाने की कोशिश कर रहे हैं, तो मैं गणना के प्रत्येक खंड को अलग-अलग (प्रत्येक संख्या या ऑपरेटर) के बजाय एक स्ट्रिंग के रूप में पास करूंगा।
इसका उत्तर देने में बहुत देर हो गई है लेकिन मुझे जावा में अभिव्यक्ति का मूल्यांकन करने के लिए एक ही स्थिति में आया, यह किसी की मदद कर सकता है
MVEL
अभिव्यक्ति का क्रम मूल्यांकन करता है, हम String
इसमें मूल्यांकन करने के लिए एक जावा कोड लिख सकते हैं ।
String expressionStr = "x+y";
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("x", 10);
vars.put("y", 20);
ExecutableStatement statement = (ExecutableStatement) MVEL.compileExpression(expressionStr);
Object result = MVEL.executeExpression(statement, vars);
आपको सिम्जा ढांचे पर एक नज़र पड़ सकती है :
ExprEvaluator util = new ExprEvaluator();
IExpr result = util.evaluate("10-40");
System.out.println(result.toString()); // -> "-30"
ध्यान दें कि निश्चित रूप से अधिक जटिल अभिव्यक्तियों का मूल्यांकन किया जा सकता है:
// D(...) gives the derivative of the function Sin(x)*Cos(x)
IAST function = D(Times(Sin(x), Cos(x)), x);
IExpr result = util.evaluate(function);
// print: Cos(x)^2-Sin(x)^2
कोड इंजेक्शन हैंडलिंग के साथ JDK1.6 के जावास्क्रिप्ट इंजन का उपयोग करके निम्नलिखित नमूना कोड का प्रयास करें।
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class EvalUtil {
private static ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
public static void main(String[] args) {
try {
System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || 5 >3 "));
System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || true"));
} catch (Exception e) {
e.printStackTrace();
}
}
public Object eval(String input) throws Exception{
try {
if(input.matches(".*[a-zA-Z;~`#$_{}\\[\\]:\\\\;\"',\\.\\?]+.*")) {
throw new Exception("Invalid expression : " + input );
}
return engine.eval(input);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
यह वास्तव में @Boann द्वारा दिए गए उत्तर का पूरक है। इसमें एक मामूली बग है, जिसके कारण -4.0 का त्रुटिपूर्ण परिणाम देने के लिए "-2 ^ 2" होता है। उसके लिए समस्या वह बिंदु है जिस पर उसके मूल्यांकन का मूल्यांकन किया जाता है। बस घातांक को parseTerm () के ब्लॉक में ले जाएँ, और आप सभी ठीक हो जाएंगे। नीचे एक नज़र डालें, जो @ Boann का उत्तर थोड़ा संशोधित है। संशोधन टिप्पणियों में है।
public static double eval(final String str) {
return new Object() {
int pos = -1, ch;
void nextChar() {
ch = (++pos < str.length()) ? str.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') nextChar();
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
return x;
}
// Grammar:
// expression = term | expression `+` term | expression `-` term
// term = factor | term `*` factor | term `/` factor
// factor = `+` factor | `-` factor | `(` expression `)`
// | number | functionName factor | factor `^` factor
double parseExpression() {
double x = parseTerm();
for (;;) {
if (eat('+')) x += parseTerm(); // addition
else if (eat('-')) x -= parseTerm(); // subtraction
else return x;
}
}
double parseTerm() {
double x = parseFactor();
for (;;) {
if (eat('*')) x *= parseFactor(); // multiplication
else if (eat('/')) x /= parseFactor(); // division
else if (eat('^')) x = Math.pow(x, parseFactor()); //exponentiation -> Moved in to here. So the problem is fixed
else return x;
}
}
double parseFactor() {
if (eat('+')) return parseFactor(); // unary plus
if (eat('-')) return -parseFactor(); // unary minus
double x;
int startPos = this.pos;
if (eat('(')) { // parentheses
x = parseExpression();
eat(')');
} else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
x = Double.parseDouble(str.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') { // functions
while (ch >= 'a' && ch <= 'z') nextChar();
String func = str.substring(startPos, this.pos);
x = parseFactor();
if (func.equals("sqrt")) x = Math.sqrt(x);
else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
else throw new RuntimeException("Unknown function: " + func);
} else {
throw new RuntimeException("Unexpected: " + (char)ch);
}
//if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation -> This is causing a bit of problem
return x;
}
}.parse();
}
-2^2 = -4
वास्तव में सामान्य है, और बग नहीं है। यह समूहबद्ध हो जाता है -(2^2)
। उदाहरण के लिए, डेसमोस पर इसे आज़माएं। आपका कोड वास्तव में कई बग का परिचय देता है। पहला यह है कि ^
अब कोई समूह दाएं-बाएं नहीं है। दूसरे शब्दों में, 2^3^2
समूह की तरह माना जाता है 2^(3^2)
क्योंकि ^
सही-सहयोगी है, लेकिन आपके संशोधन इसे समूह की तरह बनाते हैं (2^3)^2
। दूसरा यह है कि ^
माना जाता है कि इसकी तुलना में उच्च पूर्वता है *
और /
, लेकिन आपके संशोधन इसे समान मानते हैं। देखें ideone.com/iN2mMa ।
package ExpressionCalculator.expressioncalculator;
import java.text.DecimalFormat;
import java.util.Scanner;
public class ExpressionCalculator {
private static String addSpaces(String exp){
//Add space padding to operands.
//https://regex101.com/r/sJ9gM7/73
exp = exp.replaceAll("(?<=[0-9()])[\\/]", " / ");
exp = exp.replaceAll("(?<=[0-9()])[\\^]", " ^ ");
exp = exp.replaceAll("(?<=[0-9()])[\\*]", " * ");
exp = exp.replaceAll("(?<=[0-9()])[+]", " + ");
exp = exp.replaceAll("(?<=[0-9()])[-]", " - ");
//Keep replacing double spaces with single spaces until your string is properly formatted
/*while(exp.indexOf(" ") != -1){
exp = exp.replace(" ", " ");
}*/
exp = exp.replaceAll(" {2,}", " ");
return exp;
}
public static Double evaluate(String expr){
DecimalFormat df = new DecimalFormat("#.####");
//Format the expression properly before performing operations
String expression = addSpaces(expr);
try {
//We will evaluate using rule BDMAS, i.e. brackets, division, power, multiplication, addition and
//subtraction will be processed in following order
int indexClose = expression.indexOf(")");
int indexOpen = -1;
if (indexClose != -1) {
String substring = expression.substring(0, indexClose);
indexOpen = substring.lastIndexOf("(");
substring = substring.substring(indexOpen + 1).trim();
if(indexOpen != -1 && indexClose != -1) {
Double result = evaluate(substring);
expression = expression.substring(0, indexOpen).trim() + " " + result + " " + expression.substring(indexClose + 1).trim();
return evaluate(expression.trim());
}
}
String operation = "";
if(expression.indexOf(" / ") != -1){
operation = "/";
}else if(expression.indexOf(" ^ ") != -1){
operation = "^";
} else if(expression.indexOf(" * ") != -1){
operation = "*";
} else if(expression.indexOf(" + ") != -1){
operation = "+";
} else if(expression.indexOf(" - ") != -1){ //Avoid negative numbers
operation = "-";
} else{
return Double.parseDouble(expression);
}
int index = expression.indexOf(operation);
if(index != -1){
indexOpen = expression.lastIndexOf(" ", index - 2);
indexOpen = (indexOpen == -1)?0:indexOpen;
indexClose = expression.indexOf(" ", index + 2);
indexClose = (indexClose == -1)?expression.length():indexClose;
if(indexOpen != -1 && indexClose != -1) {
Double lhs = Double.parseDouble(expression.substring(indexOpen, index));
Double rhs = Double.parseDouble(expression.substring(index + 2, indexClose));
Double result = null;
switch (operation){
case "/":
//Prevent divide by 0 exception.
if(rhs == 0){
return null;
}
result = lhs / rhs;
break;
case "^":
result = Math.pow(lhs, rhs);
break;
case "*":
result = lhs * rhs;
break;
case "-":
result = lhs - rhs;
break;
case "+":
result = lhs + rhs;
break;
default:
break;
}
if(indexClose == expression.length()){
expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose);
}else{
expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose + 1);
}
return Double.valueOf(df.format(evaluate(expression.trim())));
}
}
}catch(Exception exp){
exp.printStackTrace();
}
return 0.0;
}
public static void main(String args[]){
Scanner scanner = new Scanner(System.in);
System.out.print("Enter an Mathematical Expression to Evaluate: ");
String input = scanner.nextLine();
System.out.println(evaluate(input));
}
}
इस जैसे किसी और के बारे में क्या राय है:
String st = "10+3";
int result;
for(int i=0;i<st.length();i++)
{
if(st.charAt(i)=='+')
{
result=Integer.parseInt(st.substring(0, i))+Integer.parseInt(st.substring(i+1, st.length()));
System.out.print(result);
}
}
और तदनुसार हर दूसरे गणितीय ऑपरेटर के लिए इसी तरह की बात करें ।।
जिक्सर के शंटिंग-यार्ड एल्गोरिथ्म का उपयोग करके किसी भी अभिव्यक्ति स्ट्रिंग को इन्फिक्स नोटेशन में पोस्टफिक्स नोटेशन में परिवर्तित करना संभव है । एल्गोरिथ्म का परिणाम तब पोस्टफिक्स एल्गोरिथ्म के इनपुट के रूप में काम कर सकता है अभिव्यक्ति के परिणाम के साथ ।
मैंने जावा में एक कार्यान्वयन के साथ, इसके बारे में एक लेख लिखा था
फिर भी एक अन्य विकल्प: https://github.com/stefanerateein/expressionparser
मैंने इसे लागू करने के लिए दोनों को अनुमति देने के लिए एक सरल लेकिन लचीला विकल्प दिया है:
ऊपर जुड़ा ट्रीबर्स्टल एक कैस डेमो पैकेज का हिस्सा है जो प्रतीकात्मक व्युत्पत्ति करता है। एक बेसिक दुभाषिया उदाहरण भी है और मैंने इसका उपयोग करके टाइपस्क्रिप्ट इंटरप्रेटर का निर्माण करना शुरू कर दिया है।
एक जावा वर्ग जो गणितीय अभिव्यक्तियों का मूल्यांकन कर सकता है:
package test;
public class Calculator {
public static Double calculate(String expression){
if (expression == null || expression.length() == 0) {
return null;
}
return calc(expression.replace(" ", ""));
}
public static Double calc(String expression) {
if (expression.startsWith("(") && expression.endsWith(")")) {
return calc(expression.substring(1, expression.length() - 1));
}
String[] containerArr = new String[]{expression};
double leftVal = getNextOperand(containerArr);
expression = containerArr[0];
if (expression.length() == 0) {
return leftVal;
}
char operator = expression.charAt(0);
expression = expression.substring(1);
while (operator == '*' || operator == '/') {
containerArr[0] = expression;
double rightVal = getNextOperand(containerArr);
expression = containerArr[0];
if (operator == '*') {
leftVal = leftVal * rightVal;
} else {
leftVal = leftVal / rightVal;
}
if (expression.length() > 0) {
operator = expression.charAt(0);
expression = expression.substring(1);
} else {
return leftVal;
}
}
if (operator == '+') {
return leftVal + calc(expression);
} else {
return leftVal - calc(expression);
}
}
private static double getNextOperand(String[] exp){
double res;
if (exp[0].startsWith("(")) {
int open = 1;
int i = 1;
while (open != 0) {
if (exp[0].charAt(i) == '(') {
open++;
} else if (exp[0].charAt(i) == ')') {
open--;
}
i++;
}
res = calc(exp[0].substring(1, i - 1));
exp[0] = exp[0].substring(i);
} else {
int i = 1;
if (exp[0].charAt(0) == '-') {
i++;
}
while (exp[0].length() > i && isNumber((int) exp[0].charAt(i))) {
i++;
}
res = Double.parseDouble(exp[0].substring(0, i));
exp[0] = exp[0].substring(i);
}
return res;
}
private static boolean isNumber(int c) {
int zero = (int) '0';
int nine = (int) '9';
return (c >= zero && c <= nine) || c =='.';
}
public static void main(String[] args) {
System.out.println(calculate("(((( -6 )))) * 9 * -1"));
System.out.println(calc("(-5.2+-5*-5*((5/4+2)))"));
}
}
जावास्क्रिप्ट को चलाने के लिए RHINO या NASHORN जैसी बाहरी लाइब्रेरी का उपयोग किया जा सकता है। और जावास्क्रिप्ट स्ट्रिंग को पार किए बिना सरल सूत्र का मूल्यांकन कर सकता है। कोई प्रदर्शन प्रभाव और साथ ही अगर कोड अच्छी तरह से लिखा गया है। नीचे राइनो के साथ एक उदाहरण दिया गया है -
public class RhinoApp {
private String simpleAdd = "(12+13+2-2)*2+(12+13+2-2)*2";
public void runJavaScript() {
Context jsCx = Context.enter();
Context.getCurrentContext().setOptimizationLevel(-1);
ScriptableObject scope = jsCx.initStandardObjects();
Object result = jsCx.evaluateString(scope, simpleAdd , "formula", 0, null);
Context.exit();
System.out.println(result);
}
import java.util.*;
public class check {
int ans;
String str="7 + 5";
StringTokenizer st=new StringTokenizer(str);
int v1=Integer.parseInt(st.nextToken());
String op=st.nextToken();
int v2=Integer.parseInt(st.nextToken());
if(op.equals("+")) { ans= v1 + v2; }
if(op.equals("-")) { ans= v1 - v2; }
//.........
}