中缀表达式解析器的特点:
- 可自定义函数、并且函数可任意嵌套的中缀表达式转化成声明函数参数个数的后缀表达式
- 支持算术运算和逻辑运算
- {}用来表示优先级,()用来标识自定义函数的参数列表
示例:
中缀表达式max(abs(random(-9,-1)),random(1,9))-3>0转化成声明函数参数个数的后缀表达式:-9,-1,2,random,(),1,abs,(),1,9,2,random,(),2,max,(),3,-,0,> (其中粗体数字为函数参数个数)
主要思路:
下面直接给出中缀表达式解析器的完整代码,包含有完整注释:
using System.Collections;
using System.Collections.Generic;
public class InToPostTransfer
{
private static List<string> operatorList = new List<string>()
{
"!",
"+",
"-",
"*",
"/",
"%",
">",
"<",
">=",
"<=",
"==",
"!=",
"&&",
"||",
"=",
"&",
"|",
};
private static Dictionary<string, string> inPostMapper = new Dictionary<string, string>();
private static Dictionary<string, int> funcParamrterCountMap = new Dictionary<string, int>();
private static int customFuncIndex;
public static string InToPost(string infixExpression)
{
customFuncIndex = 0;
funcParamrterCountMap.Clear();
bool isPreOperator = false;
string postfixExpression = string.Empty;
if (inPostMapper.TryGetValue(infixExpression, out postfixExpression))
{
return postfixExpression;
}
int index = 0;
Stack<string> stack = new Stack<string>();
int lastIndexOfOperator = 0;
string operatorCurrent;
string operatorInStacktop = string.Empty;
int lastIndexOfOperand = 0;
string operandCurrent = string.Empty;
int lastIndexOfCustomFunction = 0;
string customFunction = string.Empty;
int parameterCount = 0;
int lastIndexOfString = 0;
string stringInExpression = string.Empty;
while (index < infixExpression.Length || stack.Count > 0)
{
if (index >= infixExpression.Length) //last something
{
postfixExpression += stack.Pop() + ",";
}else if (infixExpression[index] == '{') //{
{
isPreOperator = false;
stack.Push("{");
index++;
continue;
}
else if (infixExpression[index] == '}')
{
isPreOperator = false;
operatorInStacktop = stack.Pop().ToString();
while (operatorInStacktop != "{")
{
postfixExpression += operatorInStacktop + ",";
operatorInStacktop = stack.Pop().ToString();
}
index++;
continue;
}
else if (infixExpression[index] == '(' || infixExpression[index] == ',')
{
isPreOperator = true;
index++;
continue;
}
else if (infixExpression[index] == ' ')
{
index++;
continue;
}
else if (infixExpression[index] == ')')
{
isPreOperator = false;
customFunction = stack.Pop().ToString();
parameterCount = funcParamrterCountMap[customFunction];
string customFuncName = customFunction.Substring(0, customFunction.LastIndexOf("_"));
postfixExpression += parameterCount.ToString() + "," + customFuncName + ",(),";
index++;
}
else if (infixExpression[index] == '\'')
{
lastIndexOfString = GetString(infixExpression, index);
stringInExpression = infixExpression.Substring(index + 1, lastIndexOfString - index - 1);
postfixExpression += stringInExpression + ",";
index = lastIndexOfString + 1;
}
else
{
lastIndexOfOperator = MatchOperator(infixExpression, index);
if (lastIndexOfOperator != -1) //operator
{
operatorCurrent = infixExpression.Substring(index, lastIndexOfOperator - index);
if (isPreOperator == true && operatorCurrent == "-")
{
postfixExpression += operatorCurrent;
index = lastIndexOfOperator;
isPreOperator = false;
continue;
}
isPreOperator = true;
if (stack.Count == 0)
{
stack.Push(operatorCurrent);
index = lastIndexOfOperator;
continue;
}
operatorInStacktop = stack.Peek().ToString();
if (GetOperatorPriority(operatorCurrent) > GetOperatorPriority(operatorInStacktop))
{
stack.Push(operatorCurrent);
index = lastIndexOfOperator;
continue;
}
else
{
postfixExpression += stack.Pop() + ",";
stack.Push(operatorCurrent);
index = lastIndexOfOperator;
continue;
}
}
else //operand
{
lastIndexOfOperand = GetOperand(infixExpression, index);
if (lastIndexOfOperand != -1)
{
isPreOperator = false;
operandCurrent = infixExpression.Substring(index, lastIndexOfOperand - index);
postfixExpression += operandCurrent + ",";
index = lastIndexOfOperand;
continue;
}
else //custom function
{
isPreOperator = false;
lastIndexOfCustomFunction = GetCustomFunction(infixExpression, index);
customFunction = infixExpression.Substring(index, lastIndexOfCustomFunction - index) + "_" + customFuncIndex;
customFuncIndex++;
funcParamrterCountMap.Add(customFunction, GetFuncParameterCount(infixExpression, lastIndexOfCustomFunction + 1));
stack.Push(customFunction);
index = lastIndexOfCustomFunction;
continue;
}
}
}
}
postfixExpression = postfixExpression.Substring(0, postfixExpression.Length - 1);
inPostMapper[infixExpression] = postfixExpression;
return postfixExpression;
}
private static int MatchOperator(string infixExpression, int beginIndex)
{
int lastIndex = beginIndex;
string str = infixExpression.Substring(beginIndex, lastIndex - beginIndex + 1);
while (operatorList.Contains(str) && lastIndex < infixExpression.Length)
{
lastIndex++;
if (lastIndex == infixExpression.Length)
{
continue;
}
str = infixExpression.Substring(beginIndex, lastIndex - beginIndex + 1);
}
if (lastIndex == beginIndex)
{
lastIndex = -1;
}
return lastIndex;
}
private static int GetOperand(string infixExpression, int beginIndex)
{
int lastIndex = beginIndex;
char ch = infixExpression[lastIndex];
switch (ch)
{
case 't':
if (infixExpression.Substring(beginIndex, 4) == "true")
{
lastIndex = beginIndex + 4;
}
break;
case 'f':
if (infixExpression.Substring(beginIndex, 5) == "false")
{
lastIndex = beginIndex + 5;
}
break;
default:
while ( (char.IsDigit(ch) || ch == '.') && lastIndex < infixExpression.Length )
{
lastIndex++;
if (lastIndex == infixExpression.Length)
{
continue;
}
ch = infixExpression[lastIndex];
}
break;
}
if (lastIndex == beginIndex)
{
lastIndex = -1;
}
return lastIndex;
}
private static int GetCustomFunction(string infixExpression, int beginIndex)
{
int lastIndex = beginIndex;
char ch = infixExpression[lastIndex];
while (ch != '(' && lastIndex < infixExpression.Length )
{
lastIndex++;
if (lastIndex == infixExpression.Length)
{
continue;
}
ch = infixExpression[lastIndex];
}
return lastIndex;
}
private static Stack<char> stackParam = new Stack<char>();
private static int GetFuncParameterCount(string infixExpression, int beginIndex)
{
stackParam.Clear();
int parametrCount = 1;
int index = beginIndex;
char ch = infixExpression[index];
if (ch == ')')
{
parametrCount = 0;
}
while (ch != ')' )
{
if (ch == '(')
{
stackParam.Push(ch);
}
else if ((ch == ',' || ch.Equals(','))
&& stackParam.Count == 0)
{
parametrCount++;
}
ch = infixExpression[++index];
while (ch == ')' && stackParam.Count != 0)
{
stackParam.Pop();
ch = infixExpression[++index];
}
}
return parametrCount;
}
private static int GetString(string infixExpression, int beginIndex)
{
int lastIndex = beginIndex + 1;
char ch = infixExpression[lastIndex];
while (ch != '\'')
{
lastIndex++;
ch = infixExpression[lastIndex];
}
return lastIndex;
}
private static int GetOperatorPriority(string ope)
{
switch (ope)
{
case "||":
return 1;
case "&&":
return 2;
case "==":
return 3;
case "!=":
return 3;
case "<=":
return 4;
case ">=":
return 4;
case "<":
return 4;
case ">":
return 4;
case "+":
return 5;
case "-":
return 5;
case "*":
return 6;
case "/":
return 6;
case "%":
return 6;
case "!":
return 7;
case "{":
return 0;
default:
return -1;
}
}
}