考虑了各种可能会出现的bug情况,使用正则表达式或抛异常处理
支持的函数有:
“abs”, “asin”, “acos”, “atan”, “cos”, “pow”, “random”, “sin”, “sqrt”, “tan”, “log”, “ln”
和普通的+ - * /,
也支持有变量,不过变量格式仅允许非数字非普通操作符的各种字符,且默认为1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace test
{
class Expression
{
public Expression(string exp)
{
expressionString = exp;
}
public void Run(out string temp, Dictionary<string, double> V)
{
temp = expressionString;
PreDo(temp);
ClearBlackSpace(ref temp);
getVariable(temp);
if (V.Count > 0)
changeVariableValue(V);
}
private string expressionString = string.Empty;
private static string[] specialOperator = new string[] { "abs", "asin", "acos", "atan", "cos", "pow", "random", "sin", "sqrt", "tan", "log", "ln" };
private static char[] commonOperator = new char[] { '+', '-', '*', '/', '(', ')', '.', '^', ',', '%' };
private Dictionary<string, double> variable = new Dictionary<string, double>();//变量字典
private int specialLongest = 0;
private void getspecialLongest()
{
foreach (var item in specialOperator)
{
specialLongest = specialLongest > item.Length ? specialLongest : item.Length;
}
}
private bool CheckBrackets(string str)
{
int mark = 0;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '(')
{
mark += 1;
}
if (str[i] == ')')
{
if (mark == 0)
return false;
else mark -= 1;
}
}
if (mark == 0)
return true;
return false;
}
private void modifyString(ref string str)//先实现替换(-,增加0,变成(0-,同理(+,后期实现3sin()之间无符号
{
if (str.StartsWith("%") || str.StartsWith("^") || str.StartsWith("*") || str.StartsWith("/"))
throw new Exception("字符串不能以运算符开头");
if (str.StartsWith("-") || str.StartsWith("+"))
str = "0" + str;
foreach (var item in specialOperator)
{
str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + item.ToString(), "$1*" + item.ToString());
}
str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + "Math.PI", "$1*Math.PI");
str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + "Math.E", "$1*Math.E");
str = System.Text.RegularExpressions.Regex.Replace(str, "Math.PI" + @"(\w)", "Math.PI*$1");
str = System.Text.RegularExpressions.Regex.Replace(str, "Math.E" + @"(\w)", "Math.E*$1");
str = System.Text.RegularExpressions.Regex.Replace(str, "Math.PI", Math.PI.ToString());
str = System.Text.RegularExpressions.Regex.Replace(str, "Math.E", Math.E.ToString());
str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + "\\(", "$1*(");
str = System.Text.RegularExpressions.Regex.Replace(str, "\\)" + "\\(", ")*(");
str = System.Text.RegularExpressions.Regex.Replace(str, @"(\d)([a-zA-Z])", "$1*$2");
str = System.Text.RegularExpressions.Regex.Replace(str, @"([a-zA-Z])(\d)", "$1*$2");
str = System.Text.RegularExpressions.Regex.Replace(str, @"([\\~\\!\\@\\#\\$\\&\\=\\?\\>\\<\\:\\;\\'""])(\w)", "$1*$2");
str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)([\\~\\!\\@\\#\\$\\&\\=\\?\\>\\<\\:\\;\\'""])", "$1*$2");
str = System.Text.RegularExpressions.Regex.Replace(str, @"([\\~\\·\\!\\@\\#\\¥\\&\\(\\)\\?\\/\\。\\,\\|\\、\\/\\:\\;\\'\\“\\”])(\w)", "$1*$2");
str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)([\\~\\·\\!\\@\\#\\¥\\&\\(\\)\\?\\/\\。\\,\\|\\、\\/\\:\\;\\'\\“\\”])", "$1*$2");
str = str.Replace("(-", "(0-");
str = str.Replace("(+", "(0+");
}
//先判断是否为空
private void PreDo(string exp)
{
if (string.IsNullOrEmpty(exp))
{
throw new Exception("表达式为空");
}
if (!CheckBrackets(exp))
{
throw new Exception("括号不匹配");
}
getspecialLongest();
}
//求变量,组成字典
private void modifyVariableDict(ref Dictionary<string, double> variable)
{
Dictionary<string, double> dic1desc2
= (from d in variable
orderby d.Key.Length descending
select d).ToDictionary(k => k.Key, v => v.Value);
variable = new Dictionary<string, double>(dic1desc2);
}
private void getVariable(string exp)
{
string tempString = exp;
tempString = System.Text.RegularExpressions.Regex.Replace(tempString, @"\d", "");
foreach (var item in specialOperator)
{
tempString = tempString.Replace(item + "(", "");
}
string[] strs = tempString.Split(commonOperator);
foreach (var item in strs)
{
if (item != " " && item != "" && !variable.ContainsKey(item))
variable.Add(item, 1);
}
modifyVariableDict(ref variable);
}
public Dictionary<string, double> displayVariable()
{
return this.variable;
}
private bool isInVariable(string str)
{
foreach (var obj in variable)
{
if (obj.Key.Equals(str))
return true;
}
return false;
}
public void changeVariableValue(Dictionary<string, double> V)
{
foreach (var item in V)
{
if (isInVariable(item.Key))
{
variable[item.Key] = item.Value;
}
}
}
//预处理字符串,去除表达式为空,括号不匹配等问题
private void ClearBlackSpace(ref string exp)
{
exp = exp.Replace(" ", "").Replace("\t", "").Replace("\r", "").Replace("\n", "");
if (string.IsNullOrEmpty(exp))
{
throw new Exception("表达式为空");
}
modifyString(ref exp);
}
//重构string
//参数值传入字符串,用参数值替换参数
private void addValueToString(ref string exp, Dictionary<string, double> V)
{
foreach (var item in variable)
{
string pattern = string.Empty;
if (item.Key != "?" && item.Key != "$")
pattern = item.Key + "(?=[^(])";
else
pattern = "\\" + item.Key + "(?=[^(])";
Regex regex = new Regex(pattern);
string result = string.Empty;
result = regex.Replace(exp, "(" + item.Value + ")");
if (item.Key != "?" && item.Key != "$")
pattern = item.Key + "$";
else
pattern = "\\" + item.Key + "$";
regex = new Regex(pattern);
result = regex.Replace(result, "(" + item.Value + ")");
exp = result;
}
}
private bool isNum(char c)
{
return (c >= '0' && c <= '9');
}
private bool isInCommonOperator(char ch)
{
foreach (var item in commonOperator)
{
if (item.Equals(ch))
{
return true;
}
}
return false;
}
private bool isInSpecialOperator(string c)
{
foreach (var item in specialOperator)
{
if (item.Equals(c))
{
return true;
}
}
return false;
}
//判断优先级
private char Precede(char a, char b)
{
switch (a)
{
case '^':
{
switch (b)
{
case '+': return '>';
case '-': return '>';
case '*': return '>';
case '/': return '>';
case '(': return '<';
case ')': return '>';
case '#': return '>';
case '%': return '>';
case '^': return '>';
case ',': return '>';
default: return ' ';
}
}
case '%':
{
switch (b)
{
case '+': return '>';
case '-': return '>';
case '*': return '>';
case '/': return '>';
case '(': return '<';
case ')': return '>';
case '#': return '>';
case '^': return '<';
case '%': return '>';
case ',': return '>';
default: return ' ';
}
}
case '+':
{
switch (b)
{
case '+': return '>';
case '-': return '>';
case '*': return '<';
case '/': return '<';
case '(': return '<';
case ')': return '>';
case '#': return '>';
case '^': return '<';
case '%': return '<';
case ',': return '>';
default: return ' ';
}
}
case '-':
{
switch (b)
{
case '+': return '>';
case '-': return '>';
case '*': return '<';
case '/': return '<';
case '(': return '<';
case ')': return '>';
case '^': return '<';
case '#': return '>';
case '%': return '<';
case ',': return '>';
default: return ' ';
}
}
case '*':
{
switch (b)
{
case '+': return '>';
case '-': return '>';
case '*': return '>';
case '/': return '>';
case '(': return '<';
case ')': return '>';
case '^': return '<';
case '%': return '>';
case '#': return '>';
case ',': return '>';
default: return ' ';
}
}
case '/':
{
switch (b)
{
case '+': return '>';
case '-': return '>';
case '*': return '>';
case '/': return '>';
case '(': return '<';
case ')': return '>';
case '#': return '>';
case '^': return '<';
case '%': return '>';
case ',': return '>';
default: return ' ';
}
}
case '(':
{
switch (b)
{
case '+': return '<';
case '-': return '<';
case '*': return '<';
case '/': return '<';
case '(': return '<';
case ')': return '=';
case '^': return '<';
case '%': return '<';
// case ',': return '>';
default: return ' ';
}
}
case ')':
{
switch (b)
{
case '+': return '>';
case '-': return '>';
case '*': return '>';
case '/': return '>';
case ')': return '>';
case '^': return '>';
case '#': return '>';
case '%': return '>';
case ',': return '>';
default: return ' ';
}
}
case '#':
{
switch (b)
{
case '+': return '<';
case '-': return '<';
case '*': return '<';
case '/': return '<';
case '(': return '<';
case '#': return '=';
case '^': return '<';
case '%': return '<';
default: return ' ';
}
}
default:
return ' ';
}
}
private double Operate(double a = 0.0, char c = ' ', double b = 0.0)
{
switch (c)
{
case '+': return (a + b);
case '-': return (a - b);
case '*': return (a * b);
case '/': return (a / b);
case '^': return Math.Pow(a, b);
case '%': return a % (b > 0 ? b : 1);
default: return 0.0;
}
}
private double SpecialOperate(string s, double a, double b = 0.0)
{//"abs", "asin", "acos", "atan", "cos", "pow", "random", "sin", "sqrt", "tan"
switch (s)
{
case "abs":
{
return Math.Abs(a);
}
case "asin":
{
return Math.Asin(a);
}
case "acos":
{
return Math.Acos(a);
}
case "atan":
{
return Math.Atan(a);
}
case "cos":
{
return Math.Cos(a);
}
case "ln":
{
return Math.Log(a);
}
case "pow":
{
return Math.Pow(b, a);
}
case "log":
{
if (b > 0 && b != 1)
{
return Math.Log(a, b);
}
else
return 0.0;
}
case "random":
{
double m_max = a > b ? a : b;
double m_min = a < b ? a : b;
int min = Convert.ToInt32(m_min);
int max = Convert.ToInt32(m_max);
return new Random().Next(min, max);
}
case "sin":
{
return Math.Sin(a);
}
case "sqrt":
{
if (a < 0) throw new Exception("sqrt函数输入参数不能小于0");
return Math.Sqrt(a);
}
case "tan":
{
return Math.Tan(a);
}
default:
{
return 0.0; //控制不会走到这里
}
}
}
private Stack<char> operateStack = new Stack<char>();//运算符
private Stack<double> numberStack = new Stack<double>();//数字
private Stack<string> specialOperateStack = new Stack<string>();//特殊运算符
private List<char> StringToList(string str)
{
List<char> lst = new List<char>();
foreach (var item in str)
{
lst.Add(item);
}
return lst;
}
//判断对应的(是不是特殊符号的(,如果是特殊运算
private bool isMatchSpecialLeftBrackets(List<char> temp, int leftIndex)
{
return (leftIndex > 0 && temp[leftIndex].Equals('(') && !isInCommonOperator(temp[leftIndex - 1]));
}
//)对应的(
private int LocateMatchIndex(List<char> temp, int rightIndex)
{
int mark = 1;
for (int i = rightIndex - 1; i >= 1; i--)
{
if (temp[i] == ')')
mark += 1;
else if (temp[i] == '(')
mark -= 1;
if (mark == 0)
return i;
}
return -1;
}
//符合:
//+( -( *( /((( ^( , ( %(
//()
//)+ )- )* )/ )) )^ )% ),
private bool isDoubleCommonEnableTeam(char a, char b)
{
if (a == '.' || b == '.')
return false;
if (isInCommonOperator(a) && b == '(')
return true;
else if (b != '(' && isInCommonOperator(b) && a == ')')
return true;
else if (a.Equals('(') && b.Equals(')'))
return true;
else return false;
}
private void CommonOperatorNotMatchWarning(int current, List<char> expChar, char ch)
{
if ((operateStack.Peek() == '(' && ch == '#') || (operateStack.Peek() == ')' && ch == '(') || (operateStack.Peek() == '#' && ch == ')'))
throw new Exception("符号不匹配");
if (current > 0 && isInCommonOperator(expChar[current - 1]) && isInCommonOperator(ch))
{
if (!isDoubleCommonEnableTeam(expChar[current - 1], ch))
throw new Exception("符号不匹配");
}
}
//计算表达式
public double Calculate(Dictionary<string, double> V)
{
string exp;
Run(out exp, V);
addValueToString(ref exp, V);
modifyString(ref exp);
bool num_realm = false;
bool xiaoshu_realm = false;
int xiaoshu_weishu = 0;
int pointOccurTime = 0;//避免搞事情,出现多个点
List<char> expChar = StringToList(exp);
expChar.Add('#'); // 借助特俗标志#来控制结束
int specialRealm = 0;//既做标志位,也做次数判断
int current = 0;
char ch = expChar[current];
operateStack.Push('#');
//先入栈
while (ch != '#' || operateStack.Peek() != '#')
{
if (isNum(ch))
{
if (num_realm && !xiaoshu_realm)//二位数或更多位数
{
double e = numberStack.Pop();
int newNum = (int)(ch - '0');
//e = e * 10 + (e > 0 ? newNum : -1 * newNum);
e = e * 10 + newNum;
numberStack.Push(e);
}
else if (num_realm && xiaoshu_realm)//小数部分
{
xiaoshu_weishu += 1;
double e = numberStack.Pop();
double newNum = (int)(ch - '0') * Math.Pow(0.1, xiaoshu_weishu);
// e = e + (e > 0 ? newNum : -1 * newNum);
e += newNum;
numberStack.Push(e);
}
else//第一位整数
{
numberStack.Push(ch - '0');
num_realm = true;
}
if (current < expChar.Count - 1)
{
ch = expChar[++current];
}
}
else
{
if (num_realm && ch == '.')
{
pointOccurTime += 1;
if (pointOccurTime < 2)
{
xiaoshu_realm = true;
if (current < expChar.Count - 1)
{
ch = expChar[++current];
}
}
else
{
throw new Exception("出现多个小数点的错误");
}
}
else if (isInCommonOperator(ch) || ch.Equals('#'))//常规运算符或结束符号
{
pointOccurTime = xiaoshu_weishu = 0;
num_realm = xiaoshu_realm = false;
CommonOperatorNotMatchWarning(current, expChar, ch);
switch (Precede(operateStack.Peek(), ch))
{
case '<': //后面的大,压入
{
operateStack.Push(ch);
if (current < expChar.Count - 1)
{
ch = expChar[++current];
}
break;
}
case '>':
{
if (numberStack.Count >= 2)
{
char theta;
double a, b;
a = numberStack.Pop();
b = numberStack.Pop();
theta = operateStack.Pop();
numberStack.Push(Operate(b, theta, a));
}
break;
}
case '=':
{
operateStack.Pop();
int indexOfRight = current;
int leftIndex = LocateMatchIndex(expChar, current);
if (isMatchSpecialLeftBrackets(expChar, leftIndex) && specialRealm > 0)
{
specialRealm -= 1;
double num1 = numberStack.Pop();
if (specialOperateStack.Peek() != "random" && specialOperateStack.Peek() != "pow" && specialOperateStack.Peek() != "log")
{
numberStack.Push(SpecialOperate(specialOperateStack.Pop(), num1));
}
else
{
double num2 = numberStack.Pop();
numberStack.Push(SpecialOperate(specialOperateStack.Pop(), num1, num2));
}
}
if (current < expChar.Count - 1)
{
ch = expChar[++current];
}
break;
}
default: { break; }
}
if (ch == ',' && current < expChar.Count - 1)
{
ch = expChar[++current];
}
else if (ch == '.' && current >= expChar.Count - 1)
{
throw new Exception("溢出或字符串匹配不正确");
}
}
else//特殊运算符
{
StringBuilder specialBuilder = new StringBuilder();
specialBuilder.Append(ch.ToString());
while (!isInSpecialOperator(specialBuilder.ToString()) && current < expChar.Count - 1 && specialBuilder.Length <= specialLongest)
{
ch = expChar[++current];
specialBuilder.Append(ch.ToString());
}
if (!isInSpecialOperator(specialBuilder.ToString()))
throw new Exception("出现未知异常");
else
{
specialOperateStack.Push(specialBuilder.ToString());
specialRealm += 1;
}
ch = expChar[++current];
}
}
}
return numberStack.Peek();
}
}
public class totalData//包含变量和字符串的类结构
{
private string exp;
public totalData(string s)
{
exp = s;
string temp = exp;
Expression e = new Expression(exp);
e.Run(out temp, new Dictionary<string, double>());
this.temporaryDict = e.displayVariable();
}
public void changeVariable(Dictionary<string, double> t)
{
string temp = exp;
Expression e = new Expression(exp);
e.Run(out temp, t);
this.temporaryDict = e.displayVariable();
}
private Dictionary<string, double> temporaryDict;
public double operationResult()
{
return new Expression(exp).Calculate(temporaryDict);
}
public Dictionary<string, double> getVariableDict()
{
return this.temporaryDict;
}
}
class Program
{
static void Main(String[] args)
{
string s = Console.ReadLine();
Console.WriteLine(new totalData(s).operationResult().ToString("0.00"));
}
}
}