我是 C# 初学者。我在将字符串转换为数学表达式时遇到问题。我有一个用户界面,用户可以使用随机公式字段创建公式。在另一个用户界面中,用户将输入这些公式字段。
例如,第一次的公式可能是
(a+b)^n
,而另一个公式可能是((a+b+c)^n+b)
。
在我的计算 UI 中,第一次用户将输入 a、b、n,第二个公式用户将输入 a、b、c、n。谁能帮助我了解如何以编程方式获得两个公式的结果?预先感谢
应该这样做:
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;
}
}
像这样调用类和方法:
string formula = "type your formula here"; //or get it from DB
StringToFormula stf = new StringToFormula();
double result = stf.Eval(formula);
我认为这就是解决方案
Expression e = new Expression("((a+b+c)^n+b)");
e.Evaluate();
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;
我想到的最具结构性的方法是定义一个由运算符符号(在你的例子中显然是 +、-、*、/ 和 ^)和操作数组成的语法;然后,如果定义的语法中存在输入的推导,则该推导基本上是表达式树,然后可以递归地遍历该表达式树,同时将运算符直接转换为实际操作。我承认描述有点模糊,但是良好的解析可能有点困难。也许看看 LL 解析器 会有所帮助。
将字符串转换为数学表达式
var s3 = "3 - 4 + 5 * 9"
var s4 = NSExpression(format: s3).expressionValue(with: nil, context: nil) as! Double // 44.0
答案:44
旧帖子,但我喜欢发布的解决方案源,并认为我会发布一个固定版本。它使用上面发布的源,但现在可以正确计算具有运算符优先级和负数的结果。例如。
10 + 12*10 - -47 % 30.0 = 147
或 -2 + -4 * (-2 - -2*10) = -74
public static class StringToFormula
{
private static readonly string[] operators = { "+", "-", "/", "%", "*", "^" };
private static readonly Func<double, double, double>[] operations = {
(a1, a2) => a1 + a2,
(a1, a2) => a1 - a2,
(a1, a2) => a1 / a2,
(a1, a2) => a1 % a2,
(a1, a2) => a1 * a2,
(a1, a2) => Math.Pow(a1, a2)
};
public static bool TryEval(string expression, out double value)
{
try
{
value = Eval(expression);
return true;
}
catch
{
value = 0.0;
return false;
}
}
public static double Eval(string expression)
{
if (string.IsNullOrEmpty(expression))
return 0.0;
if (double.TryParse(expression, NumberStyles.Any, CultureInfo.InvariantCulture, out double value))
return value;
List<string> tokens = GetTokens(expression);
tokens.Add("$"); // Append end of expression token
Stack<double> operandStack = new Stack<double>();
Stack<string> operatorStack = new Stack<string>();
int tokenIndex = 0;
while (tokenIndex < tokens.Count - 1)
{
string token = tokens[tokenIndex];
string nextToken = tokens[tokenIndex + 1];
switch (token)
{
case "(":
{
string subExpr = GetSubExpression(tokens, ref tokenIndex);
operandStack.Push(Eval(subExpr));
continue;
}
case ")":
throw new ArgumentException("Mis-matched parentheses in expression");
// Handle unary ops
case "-":
case "+":
{
if (!IsOperator(nextToken) && operatorStack.Count == operandStack.Count)
{
operandStack.Push(double.Parse($"{token}{nextToken}", CultureInfo.InvariantCulture));
tokenIndex += 2;
continue;
}
}
break;
}
if (IsOperator(token))
{
while (operatorStack.Count > 0 && OperatorPrecedence(token) <= OperatorPrecedence(operatorStack.Peek()))
{
if (!ResolveOperation()) {
throw new ArgumentException(BuildOpError());
}
}
operatorStack.Push(token);
}
else
{
operandStack.Push(double.Parse(token, CultureInfo.InvariantCulture));
}
tokenIndex += 1;
}
while (operatorStack.Count > 0)
{
if (!ResolveOperation())
throw new ArgumentException(BuildOpError());
}
return operandStack.Pop();
bool IsOperator(string token)
{
return Array.IndexOf(operators, token) >= 0;
}
int OperatorPrecedence(string op)
{
switch (op)
{
case "^":
return 3;
case "*":
case "/":
case "%":
return 2;
case "+":
case "-":
return 1;
default:
return 0;
}
}
string BuildOpError() {
string op = operatorStack.Pop();
string rhs = operandStack.Any() ? operandStack.Pop().ToString() : "null";
string lhs = operandStack.Any() ? operandStack.Pop().ToString() : "null";
return $"Operation not supported: {lhs} {op} {rhs}";
}
bool ResolveOperation()
{
if (operandStack.Count < 2)
{
return false;
}
string op = operatorStack.Pop();
double rhs = operandStack.Pop();
double lhs = operandStack.Pop();
operandStack.Push(operations[Array.IndexOf(operators, op)](lhs, rhs));
Console.WriteLine($"Resolve {lhs} {op} {rhs} = {operandStack.Peek()}");
return true;
}
}
private static 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];
switch (token) {
case "(": parenlevels += 1; break;
case ")": parenlevels -= 1; break;
}
if (parenlevels > 0)
subExpr.Append(token);
index += 1;
}
if (parenlevels > 0)
throw new ArgumentException("Mis-matched parentheses in expression");
return subExpr.ToString();
}
private static 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.ToString());
}
else
{
sb.Append(c);
}
}
if ((sb.Length > 0))
{
tokens.Add(sb.ToString());
}
return tokens;
}
}