public static class ExpressionEvaluation
{
/// <summary>
/// 计算表达式的值
/// </summary>
/// <param name="str">没有语法错误的表达式</param>
/// <returns>表达式的值</returns>
public static double ComputeExpressionValue(String str)
{
List<string> funcNameList = new List<string> { "Max", "Min" };
Func<List<string>, bool> HasFuncName = (List<string> funcList) =>
{
bool hasFunc = false;
for (var pos = 0; pos < funcNameList.Count; ++pos)
{
if (funcList.Contains(funcNameList[pos]))
{
hasFunc = true;
break;
}
}
return hasFunc;
};
List<String> postFix = null;
List<String> expressList = stringToArray(funcNameList,str);
if (HasFuncName(expressList))
{
do
{
var preExpress = PretreatmentExpression(funcNameList,expressList);
expressList = preExpress;
}
while (HasFuncName(expressList));
postFix = InfixConvertToPostfix(expressList);
}
else
{
postFix = InfixConvertToPostfix(expressList);
}
return PostExpressValue(postFix);
}
private static double PostExpressValue(List<String> postFix)
{
Stack<double> num = new Stack<double>();
double num1 = 0; // 接收栈顶数
double num2 = 0; // 接收次顶数
double res = 0; // 每次计算结果
foreach (String s in postFix)
{
if (s == "0")
{
num.Push(double.Parse(s));
}
else
{
string regexStr1 = @"([1-9]\d*\.\d*|0\.\d*[1-9]\d*)|[1-9]\d*";
Match match1 = Regex.Match(s, regexStr1);
if (match1.Success)
{ // 如果是数,就压栈
num.Push(double.Parse(s));
}
else
{
num1 = num.Pop();
num2 = num.Pop();
switch (s)
{
case "+":
res = num2 + num1;
break;
case "-":
res = num2 - num1;
break;
case "*":
res = num2 * num1;
break;
case "/":
res = num2 / num1;
break;
default:
throw new Exception("扫描到未知符号!");
}
num.Push(res);
}
}
}
return num.Pop();
}
private static bool isOperator(char c)
{
// 只有当遍历到以下符号时,才存储集合,其他符号过滤
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}
private static bool isNumber(char c)
{
// ascll码中数字 0 ~ 9 对应 48 ~ 57
return 48 <= c && c <= 57;
}
private static int getPriority(String s)
{
if (s.Equals("*") || s.Equals("/"))
{
return 2;
}
if (s.Equals("+") || s.Equals("-"))
{
return 1;
}
if (s.Equals("("))
{
return 0;
}
throw new Exception("扫描到未知符号!");
}
/// <summary>
/// 字符串拆分
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private static List<String> stringToArray(List<String>funcNameList,String s)
{
List<String> ls = new List<String>();
int i = 0; // 遍历 String 的索引
String str; // 拼接多位数
char c; // 每次遍历到的字符
do
{
c = s.ElementAt(i);
if (c == ' ')
{
i++;
}
else
{
if (isOperator(c))
{ // 如果遍历到的是符号,直接添加到 list
ls.Add("" + c);
i++;
}
else
{
if (isNumber(c))
{ // 如果遍历到的是一个数,需要判断是否为多位数,用 str 拼接
str = ""; // 先将 str 清空
string subStr = s.Substring(i);
string regexStr1 = @"([1-9]\d*\.\d*|0\.\d*[1-9]\d*)|[1-9]\d*";
Match match1 = Regex.Match(subStr, regexStr1);
if (match1.Success)
{
str = match1.Value;
}
else
{
str = s.Substring(i, 1);
}
ls.Add(str);
i += str.Count();
}
else
{
str = ""; // 先将 str 清空
string subStr = s.Substring(i);
foreach (var funcName in funcNameList)
{
var leftstr = subStr.ToLower();
var func = funcName.ToLower();
if (leftstr.StartsWith(func))
{
str = funcName;
}
}
if (str != "")
{//无效的字符
ls.Add(str);
i += str.Count();
}
else
{
i++;
}
}
}
}
} while (i < s.Count());
return ls;
}
/// <summary>
///
/// </summary>
/// <param name="infix"></param>
/// <returns></returns>
private static List<String> PretreatmentExpression(List<string> funcNameList,List<string> infix)
{
List<int> funcExist = new List<int>();
for (var pos = 0; pos < funcNameList.Count;++pos)
{
var funcIndex = infix.FindIndex(it => it.Equals(funcNameList[pos]));
funcExist.Add(funcIndex);
}
int startFuncIndex = int.MaxValue;
for (var pos = 0;pos < funcExist.Count;pos++ )
{
if (funcExist[pos] != -1)
{
if (startFuncIndex > funcExist[pos])
{
startFuncIndex = funcExist[pos];
}
}
}
if (startFuncIndex != int.MaxValue)
{
string func = funcNameList[startFuncIndex];
int index = startFuncIndex;
int endPos = -1;
int startCount = 0;
for (var i = index + 1; i < infix.Count; ++i)
{
if (infix.ElementAt(i).Equals("("))
{
startCount++;
}
else
{
if (infix.ElementAt(i).Equals(")"))
{
startCount--;
}
}
if (startCount == 0)
{
endPos = i;
break;
}
}
if (endPos != -1)
{
List<String> s2 = new List<String>();
//获取函数参数
for (int i = index + 2; i < endPos; ++i)
{
s2.Add(infix[i]);
}
//有参函数
if (s2.Count != 0)
{
//判断是否有函数
bool hasFunc = false;
for (var pos = 0; pos < funcNameList.Count; ++pos)
{
if (s2.Contains(funcNameList[pos]))
{
hasFunc = true;
break;
}
}
if (hasFunc)
{
List<String> rtn = new List<String>();
for (var i = 0; i < index; ++i)
{
rtn.Add(infix[i]);
}
var subList = PretreatmentExpression(funcNameList,s2);
List<String> expressValList = new List<string>();
List<List<String>> expressList = new List<List<String>>();
GetSubExpress(subList, ref expressList);
foreach (var express in expressList)
{
if (express.Count == 1)
{
expressValList.Add(express[0]);
}
else
{
var postFix = InfixConvertToPostfix(express);
double val = PostExpressValue(postFix);
expressValList.Add(val.ToString());
}
}
switch (func)
{
case "Max":
{
double max = GetMaxValue(expressValList);
string maxStr = max.ToString();
rtn.Add(maxStr);
}
break;
case "Min":
{
double min = GetMinValue(expressValList);
string minStr = min.ToString();
rtn.Add(minStr);
}
break;
}
for (var i = endPos + 1; i < infix.Count; ++i)
{
rtn.Add(infix[i]);
}
return rtn;
}
else
{
List<String> rtn = new List<String>();
for (var i = 0; i < index; ++i)
{
rtn.Add(infix[i]);
}
List<String> expressValList = new List<string>();
if (s2.Count == 1)
{
expressValList.Add(s2[0]);
}
else
{
List<List<String>> expressList = new List<List<String>>();
GetSubExpress(s2, ref expressList);
foreach (var express in expressList)
{
if (express.Count == 1)
{
expressValList.Add(express[0]);
}
else
{
var postFix = InfixConvertToPostfix(express);
double val = PostExpressValue(postFix);
expressValList.Add(val.ToString());
}
}
}
switch (func)
{
case "Max":
{
double max = GetMaxValue(expressValList);
string maxStr = max.ToString();
rtn.Add(maxStr);
}
break;
case "Min":
{
double min = GetMinValue(expressValList);
string minStr = min.ToString();
rtn.Add(minStr);
}
break;
}
for (var i = endPos + 1; i < infix.Count; ++i)
{
rtn.Add(infix[i]);
}
return rtn;
}
}
}
else
{
throw new Exception("");
}
}
return infix;
}
private static void GetSubExpress(List<string> s2, ref List<List<string>> expressValList)
{
string regexStr1 = @"([1-9]\d*\.\d*|0\.\d*[1-9]\d*)|[1-9]\d*";
int index = 0;
for (;index < s2.Count - 1;++index)
{
Match match1 = Regex.Match(s2[index], regexStr1);
Match match2 = Regex.Match(s2[index +1], regexStr1);
List<string> express = new List<string>();
if (match1.Success && match2.Success || match1.Success && s2[index + 1] == "0" || match2.Success && s2[index] == "0" || s2[index] == "0" && s2[index + 1] == "0")
{
express.Add(s2[index]);
expressValList.Add(express);
continue;
}
int pos = index;
while (pos < s2.Count - 1)
{
express.Add(s2[pos]);
Match match3 = Regex.Match(s2[pos], regexStr1);
Match match4 = Regex.Match(s2[pos + 1], regexStr1);
if (match3.Success && match4.Success || match3.Success && s2[pos + 1] == "0" || match4.Success && s2[pos] == "0" || s2[pos] == "0" && s2[pos + 1] == "0")
{
break;
}
pos++;
}
if (pos == s2.Count - 1)
{
express.Add(s2[pos]);
}
expressValList.Add(express);
index = pos;
}
if (index == s2.Count - 1)
{
List<string> express = new List<string> { s2[index] };
expressValList.Add(express);
}
}
private static double GetMinValue(List<string> s2)
{
if (s2.Count == 2)
{
double v1 = double.Parse(s2[0]);
double v2 = double.Parse(s2[1]);
return v1 < v2 ? v1 : v2;
}
else
{
if (s2.Count == 1)
{
double v1 = double.Parse(s2[0]);
return v1;
}
else
{
double v1 = double.Parse(s2[s2.Count - 1]);
s2.RemoveAt(s2.Count - 1);
var v2 = GetMinValue(s2);
return v1 < v2 ? v1 : v2;
}
}
}
private static double GetMaxValue(List<string> s2)
{
if (s2.Count == 2)
{
double v1 = double.Parse(s2[0]);
double v2 = double.Parse(s2[1]);
return v1 > v2 ? v1 : v2;
}
else
{
if (s2.Count == 1)
{
double v1 = double.Parse(s2[0]);
return v1;
}
else
{
double v1 = double.Parse(s2[s2.Count - 1]);
s2.RemoveAt(s2.Count - 1);
var v2 = GetMaxValue(s2);
return v1 > v2 ? v1 : v2;
}
}
}
/// <summary>
/// 字符串转换为后缀表达式
/// </summary>
/// <param name="infix"></param>
/// <returns></returns>
private static List<String> InfixConvertToPostfix(List<String> express)
{
// 创建两个栈,s1 用于存储临时符号
Stack<String> s1 = new Stack<String>();
// s2 由于没有 pop 操作,并且最终需要逆序输出,所以使用 ArrayList 代替之
List<String> s2 = new List<String>();
//遍历传入的中缀表达式集合
foreach (String s in express)
{
string regexStr1 = @"[1-9]\d*\.\d*|0\.\d*[1-9]\d*|[1-9]\d*";
Match match1 = Regex.Match(s, regexStr1);
if (match1.Success)
{//正则匹配,匹配到数字,直接添加到 s2
s2.Add(match1.Value);
}
else if (s.Equals("("))
{ // 遍历到 (,直接压入 s1
s1.Push(s);
}
else if (s.Equals(")"))
{ // 遍历到 ) ,弹出 s1 中的符号添加到 s2 中,直至遇到 (
while (s1.Peek().Equals("(") == false)
{ // peek() 查看栈顶元素
s2.Add(s1.Pop());
}
s1.Pop(); // 当 ( 弹出,消除小括号
}
else
{ // 遍历到 + - * /
// s1 不为空,且当遍历到的符号,小于等于栈顶符号优先级,需要弹栈操作
// 直到当前符号优先级大于 s1 栈顶元素或 s1 弹空时,结束
while (s1.Count != 0 && (getPriority(s) <= getPriority(s1.Peek())))
{
s2.Add(s1.Pop()); // 将 s1 栈顶符号弹出添加到 s2 中
}
// 比较结束后,将当前字符压入 s1 中
s1.Push(s);
}
}
// 将 s1 中剩余符号添加到 s2 中
while (s1.Count != 0)
{
s2.Add(s1.Pop());
}
return s2;
}