问题
I am a beginner at C#. I am facing a problem while converting a string to a mathematical expression. I have a UI where user can create formula using random formula field. And in another UI user will give input of those formula field.
like for example at first time the formula may be (a+b)^n
and another the formula may be ((a+b+c)^n+b)
.
In my calculation UI for the first time user will give input for a,b,n and for 2nd formula user will give input for a,b,c,n. Can anyone please help me about how to get the result for both of the formula programmatic-ally? Thanks in advance
回答1:
This is how it should be done:
public class StringToFormula
{
private string[] _operators = { "-", "+", "/", "*","^"};
private Func<double, double, double>[] _operations = {
(a1, a2) => a1 - a2,
(a1, a2) => a1 + a2,
(a1, a2) => a1 / a2,
(a1, a2) => a1 * a2,
(a1, a2) => Math.Pow(a1, a2)
};
public double Eval(string expression)
{
List<string> tokens = getTokens(expression);
Stack<double> operandStack = new Stack<double>();
Stack<string> operatorStack = new Stack<string>();
int tokenIndex = 0;
while (tokenIndex < tokens.Count) {
string token = tokens[tokenIndex];
if (token == "(") {
string subExpr = getSubExpression(tokens, ref tokenIndex);
operandStack.Push(Eval(subExpr));
continue;
}
if (token == ")") {
throw new ArgumentException("Mis-matched parentheses in expression");
}
//If this is an operator
if (Array.IndexOf(_operators, token) >= 0) {
while (operatorStack.Count > 0 && Array.IndexOf(_operators, token) < Array.IndexOf(_operators, operatorStack.Peek())) {
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
operatorStack.Push(token);
} else {
operandStack.Push(double.Parse(token));
}
tokenIndex += 1;
}
while (operatorStack.Count > 0) {
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
return operandStack.Pop();
}
private string getSubExpression(List<string> tokens, ref int index)
{
StringBuilder subExpr = new StringBuilder();
int parenlevels = 1;
index += 1;
while (index < tokens.Count && parenlevels > 0) {
string token = tokens[index];
if (tokens[index] == "(") {
parenlevels += 1;
}
if (tokens[index] == ")") {
parenlevels -= 1;
}
if (parenlevels > 0) {
subExpr.Append(token);
}
index += 1;
}
if ((parenlevels > 0)) {
throw new ArgumentException("Mis-matched parentheses in expression");
}
return subExpr.ToString();
}
private List<string> getTokens(string expression)
{
string operators = "()^*/+-";
List<string> tokens = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in expression.Replace(" ", string.Empty)) {
if (operators.IndexOf(c) >= 0) {
if ((sb.Length > 0)) {
tokens.Add(sb.ToString());
sb.Length = 0;
}
tokens.Add(c);
} else {
sb.Append(c);
}
}
if ((sb.Length > 0)) {
tokens.Add(sb.ToString());
}
return tokens;
}
}
Call the class and method like this:
string formula = "type your formula here"; //or get it from DB
StringToFormula stf = new StringToFormula();
double result = stf.Eval(formula);
回答2:
i think this is the solution
Expression e = new Expression("((a+b+c)^n+b)");
e.Evaluate();
回答3:
There are plenty methods for formula evaluation,
take a look. Just take your input, replace a
, b
, n
chars in your string to values provided by user and resolve equation with one of methods mentioned.
回答4:
string input= "(12 + 4 * 6) * ((2 + 3 * ( 4 + 2 ) ) ( 5 + 12 ))";
string str4 = "(" + input`enter code here`.Replace(" ", "") + ")";
str4 = str4.Replace(")(", ")*(");
while (str4.Contains('('))
{
string sub1 = str4.Substring(str4.LastIndexOf("(") + 1);
string sub = sub1.Substring(0, sub1.IndexOf(")"));
string sub2 = sub;
string str21 = sub2.Replace("^", "~^~").Replace("/", "~/~").Replace("*", "~*~").Replace("+", "~+~").Replace("-", "~-~");
List<string> str31 = str21.Split('~').ToList();
while (str31.Count > 1)
{
while (str31.Contains("*"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "*")
{
val = Convert.ToDouble(str31[i - 1]) * Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("/"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "/")
{
val = Convert.ToDouble(str31[i - 1]) / Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("+"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "+")
{
val = Convert.ToDouble(str31[i - 1]) + Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
while (str31.Contains("-"))
{
for (int i = 0; i < str31.Count; i++)
{
if (str31[i] == "-")
{
val = Convert.ToDouble(str31[i - 1]) - Convert.ToDouble(str31[i + 1]);
str31.RemoveRange(i - 1, 3);
str31.Insert(i - 1, val.ToString());
}
}
}
}
str4 = str4.Replace("(" + sub + ")", str31[0].ToString());
}
string sum = str4;
回答5:
The most structural approach which comes to my mind would be to define a grammar consisting out of operator symbols (which are apparently +,-,*,/ and ^ in your case) and operands; then, if a derivation of the input in the defined grammar exists, the derivation basically is the expression tree which can then be traversed recursively while the operators are directry translated to the actual operations. I admit that the description is a bit vague, but good parsing can be a bit difficult. Perhaps a look at LL parser can help a bit.
来源:https://stackoverflow.com/questions/21750824/how-to-convert-a-string-to-a-mathematical-expression-programmatically