我经常看到这个问题,所以我写了这篇文章。这肯定会让你朝着正确的方向前进,但要小心,这是一个自顶向下的解析器,因此它可能无法按照您预期的优先级解释表达式。
class Program
{
static void Main()
{
Console.WriteLine(SimpleExpressionParser.Parse("(10+30*2)/20").ToString());
Console.ReadLine();
}
public static class SimpleExpressionParser
{
public static SimpleExpression Parse(string str)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
int index = 0;
return InternalParse(str, ref index, 0);
}
private static SimpleExpression InternalParse(string str, ref int index, int level)
{
State state = State.ExpectLeft;
SimpleExpression _expression = new SimpleExpression();
int startIndex = index;
int length = str.Length;
while (index < length)
{
char chr = str[index];
if (chr == ')' && level != 0)
{
break;
}
switch (state)
{
case State.ExpectLeft:
case State.ExpectRight:
{
SimpleExpression expression = null;
if (Char.IsDigit(chr))
{
int findRep = FindRep(Char.IsDigit, str, index + 1, length - 1);
expression = new SimpleExpression(int.Parse(str.Substring(index, findRep + 1)));
index += findRep;
}
else if (chr == '(')
{
index++;
expression = InternalParse(str, ref index, level + 1);
}
if (expression == null)
{
throw new Exception(String.Format("Expression expected at index {0}", index));
}
if (state == State.ExpectLeft)
{
_expression.Left = expression;
state = State.ExpectOperator;
}
else
{
_expression.Right = expression;
state = State.ExpectFarOperator;
}
}
break;
case State.ExpectOperator:
case State.ExpectFarOperator:
{
SimpleExpressionOperator op;
switch (chr)
{
case '+': op = SimpleExpressionOperator.Add; break;
case '-': op = SimpleExpressionOperator.Subtract; break;
case '*': op = SimpleExpressionOperator.Multiply; break;
case '/': op = SimpleExpressionOperator.Divide; break;
default:
throw new Exception(String.Format("Invalid operator encountered at index {0}", index));
}
if (state == State.ExpectOperator)
{
_expression.Operator = op;
state = State.ExpectRight;
}
else
{
index++;
return new SimpleExpression(op, _expression, InternalParse(str, ref index, level));
}
}
break;
}
index++;
}
if (state == State.ExpectLeft || state == State.ExpectRight)
{
throw new Exception("Could not complete expression");
}
return _expression;
}
private static int FindRep(Func<char, bool> validator, string str, int beginPos, int endPos)
{
int pos;
for (pos = beginPos; pos <= endPos; pos++)
{
if (!validator.Invoke(str[pos]))
{
break;
}
}
return pos - beginPos;
}
private enum State
{
ExpectLeft,
ExpectRight,
ExpectOperator,
ExpectFarOperator
}
}
public enum SimpleExpressionOperator
{
Add,
Subtract,
Multiply,
Divide
}
public class SimpleExpression
{
private static Dictionary<SimpleExpressionOperator, char> opEquivs = new Dictionary<SimpleExpressionOperator, char>()
{
{ SimpleExpressionOperator.Add, '+' },
{ SimpleExpressionOperator.Subtract, '-' },
{ SimpleExpressionOperator.Multiply, '*' },
{ SimpleExpressionOperator.Divide, '/' }
};
public SimpleExpression() { }
public SimpleExpression(int literal)
{
Literal = literal;
IsLiteral = true;
}
public SimpleExpression(SimpleExpressionOperator op, SimpleExpression left, SimpleExpression right)
{
Operator = op;
Left = left;
Right = right;
}
public bool IsLiteral
{
get;
set;
}
public int Literal
{
get;
set;
}
public SimpleExpressionOperator Operator
{
get;
set;
}
public SimpleExpression Left
{
get;
set;
}
public SimpleExpression Right
{
get;
set;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
AppendExpression(sb, this, 0);
return sb.ToString();
}
private static void AppendExpression(StringBuilder sb, SimpleExpression expression, int level)
{
bool enclose = (level != 0 && !expression.IsLiteral && expression.Right != null);
if (enclose)
{
sb.Append('(');
}
if (expression.IsLiteral)
{
sb.Append(expression.Literal);
}
else
{
if (expression.Left == null)
{
throw new Exception("Invalid expression encountered");
}
AppendExpression(sb, expression.Left, level + 1);
if (expression.Right != null)
{
sb.Append(opEquivs[expression.Operator]);
AppendExpression(sb, expression.Right, level + 1);
}
}
if (enclose)
{
sb.Append(')');
}
}
}
}