自定义表达式解析,涉及到三个主要步骤:
1.关键字析取
2.中序表达式转逆波兰表达式
3.逆波兰表达式运算。
下面给出一个示例,整个编码过程,在支持运算符有限的情况下,大约一天即可完成(C#实现),这个实现中涉及到的比较好的实现方式有两点:
1.我们生成了一个逆波兰式的中间结果,这个结果是对象化的。
2.支持中序表达式中函数的析取和逆波兰式运算时的函数扩展。
首先是调用代码:
//表达式运算示例
private void button1_Click(object sender, EventArgs e)
{
List<rpn.rpngenerator.op></rpn.rpngenerator.op> ops = rpn.RpnGenerator.GetCommonOps();
List<rpn.rpngenerator.item></rpn.rpngenerator.item> mn = rpn.RpnAnalyser.GetMn(this.textBox1.Text, ref ops);
List<rpn.rpngenerator.item></rpn.rpngenerator.item> rpn1 = rpn.RpnGenerator.GetRpnFromMn(mn);
String s = "";
foreach (rpn.RpnGenerator.ITEM i in rpn1)
{
s += i.value;
s += " ";
}
this.textBox2.Text = s;
MyRpnCalc rc = new MyRpnCalc();
textBox3.Text = rc.Calc(rpn1).value;
}
//逆波兰运算重载
class MyRpnCalc : rpn.RpnCalc
{
public override RpnGenerator.Data CalcOp(RpnGenerator.Op op, ref List<rpngenerator.data></rpngenerator.data> result)
{
RpnGenerator.Data d = new RpnGenerator.Data("");
switch (op.value)
{
case "or":
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
bool l1;
bool l2;
l1 = bool.Parse(rhs1.value);
l2 = bool.Parse(rhs2.value);
d.value = (l1 || l2).ToString();
}
break;
default:
return base.CalcOp(op, ref result);
}
return d;
}
}
}
上面的代码中处理了函数的解析,所以涉及到一个重载函数的定义,其中“or(x,y)”即是一个扩展出的自定义函数,接下来是主体部分:
/*
* rpn.cs
*
* 逆波兰表达式运算辅助函数族。本实现仅对逻辑和比较运算符进行解析,仅供参考。
*
* 内含:
* 1. 表达式析取(包含函数的自动解析、空白字符处理)
* 2. 中序表达式转逆波兰表达式
* 3. 部分逻辑运算的实现
*
* last edition: Aug28,2017
* first edition: Aug25,2017
* author: fengxh
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace rpn
{
/// <summary>
/// 表达式析取
/// </summary>
public class RpnAnalyser
{
/// <summary>
/// 完整功能的表达式析取函数
/// </summary>
/// 待解析的中序表达式<param></param>
/// 运算符集合,不应包含函数<param></param>
/// <returns>可供逆波兰转换的表达式</returns>
public static List<rpngenerator.item></rpngenerator.item> GetMn(String s, ref List<rpngenerator.op></rpngenerator.op> ops)
{
List<rpngenerator.item></rpngenerator.item> l = new List<rpngenerator.item></rpngenerator.item>();
string cur = "";
int leftMatchCnt = 0;
int rightMatchLength = 0;
while (s.Length != 0)
{
cur += s[0];
s = s.Substring(1);
RECHECK:
rightMatchLength = 0;
int oldLeftMatchCnt = leftMatchCnt;
leftMatchCnt = 0;
foreach (RpnGenerator.Op op in ops)
{
if (op.value.Length >= cur.Length && op.value.Substring(0, cur.Length) == cur) leftMatchCnt++;
if (cur.Length >= op.value.Length)
{
if (cur.Substring(cur.Length - op.value.Length, op.value.Length) == op.value)
{
rightMatchLength = op.value.Length;
}
}
}
if (leftMatchCnt == 1)
{
foreach (RpnGenerator.Op op in ops)
{
if (op.value == cur)
{
if (op.value == "(")
{
if (l.Count > 0 && (l.Last().GetType() != typeof(RpnGenerator.Op)))
{
RpnGenerator.Op o = new RpnGenerator.Op(l.Last().value, -1, 99);
l.RemoveAt(l.Count() - 1);
l.Add(o);
ops.Add((RpnGenerator.Op)o.Clone());
}
}
l.Add((RpnGenerator.Op)op.Clone());
leftMatchCnt = 0;
break;
}
}
if (leftMatchCnt == 0)
{
cur = "";
}
leftMatchCnt = 0;
}
else if (rightMatchLength > 0 && leftMatchCnt == 0 && oldLeftMatchCnt == 0)
{
RpnGenerator.Data d = new RpnGenerator.Data(cur.Substring(0, cur.Length - rightMatchLength));
cur = cur.Substring(d.value.Length, cur.Length - d.value.Length);
d.value = d.value.Trim();
if (d.value.Length > 0)
{
l.Add(d);
}
leftMatchCnt = 0;
if (cur.Length > 0) goto RECHECK;
}
else if (oldLeftMatchCnt > 0 && leftMatchCnt == 0)
{
foreach (RpnGenerator.Op op in ops)
{
if (op.value.Length == cur.Length - 1 && cur.Substring(0, op.value.Length) == op.value)
{
l.Add((RpnGenerator.Op)op.Clone());
cur = cur.Substring(op.value.Length, cur.Length - op.value.Length);
leftMatchCnt = 0;
goto RECHECK;
}
}
}
}
if (cur.Length != 0)
{
RpnGenerator.Data d = new RpnGenerator.Data(cur.Trim());
if (d.value.Length > 0)
{
l.Add(d);
}
}
return l;
}
}
/// <summary>
/// 中序->逆波兰转换
/// 本模块的输入是结构化处理过的表达式,其基本元素是RpnGenerator.ITEM
/// </summary>
public class RpnGenerator
{
/// <summary>
/// 表达式基本元素
/// </summary>
public class ITEM
{
public string value;
public ITEM(string value)
{
this.value = value;
}
}
/// <summary>
/// 操作数
/// </summary>
public class Data : ITEM
{
public Data(string value)
: base(value)
{
}
}
/// <summary>
/// 运算符
/// </summary>
public class Op : ITEM, ICloneable
{
public Op(string value)
: base(value)
{
this.cntOfData = 0;
this.priority = 0;
}
public Op(string value, int cntOfData, int priority)
:base (value)
{
this.cntOfData = cntOfData;
this.priority = priority;
}
public Object Clone()
{
return new Op(this.value, this.cntOfData, this.priority);
}
bool isOperator1() { return cntOfData == 1; }
bool isOperator2() { return cntOfData == 2; }
bool isFunction() { return cntOfData == -1; }
public int cntOfData;
public int priority;
}
/// <summary>
/// 返回内置运算符集合
/// </summary>
/// <returns>内置运算符集合</returns>
public static List<op></op> GetCommonOps()
{
List<op></op> l = new List<op></op>();
l.AddRange(new Op[] {
Op_equal,
//Op_lastOp,
Op_leftBracket,
Op_logic_and,
Op_comma,
Op_greater,
Op_greaterOrEqual,
Op_isEqual,
Op_less,
Op_lessOrEqual,
Op_logic_not,
Op_notEqual,
Op_logic_or,
Op_RightBracket
});
return l;
}
static public Op Op_lastOp = new Op("#");
static public Op Op_leftBracket = new Op("(");
static public Op Op_RightBracket = new Op(")");
static public Op Op_equal = new Op("=", 2, 10);
static public Op Op_logic_or = new Op("||", 2, 15);
static public Op Op_logic_and = new Op("&&", 2, 15);
static public Op Op_greater = new Op(">", 2, 16);
static public Op Op_greaterOrEqual = new Op(">=", 2, 16);
static public Op Op_less = new Op("<", 2, 16);
static public Op Op_lessOrEqual = new Op("<=", 2, 16);
static public Op Op_logic_not = new Op("!", 1, 17);
static public Op Op_isEqual = new Op("==", 2, 20);
static public Op Op_notEqual = new Op("!=", 2, 20);
static public Op Op_comma = new Op(",",0, 1);
/// <summary>
/// 中序表达式转逆波兰表达式
/// </summary>
/// 中序表达式<param></param>
/// <returns>逆波兰表达式</returns>
static public List<item></item> GetRpnFromMn(List<item></item> input)
{
Stack<op></op> S1 = new Stack<op></op>();
List<item></item> S2 = new List<item></item>();
S1.Push(Op_lastOp);
foreach (ITEM i in input)
{
if (i.GetType() == typeof(Data))
{
S2.Add(i);
}
if (i.GetType() == typeof(Op))
{
Op io = (Op)i;
if (io.value == "(")
{
S1.Push(io);
}
else if (io.value == ")")
{
while (S1.Peek().value != "(") S2.Add(S1.Pop());
S1.Pop();
}
else
{
if (io.priority > S1.Peek().priority) S1.Push(io);
else
{
while (S1.Peek().priority >= io.priority && !(S1.Peek().cntOfData == 1 && S1.Peek().cntOfData == io.cntOfData))
{
S2.Add(S1.Pop());
}
S1.Push(io);
}
}
}
}
if (S1.Count != 1)
{
while (S1.Count > 1) S2.Add(S1.Pop());
}
//clear comma
List<item></item> S3 = new List<item></item>();
foreach (ITEM i in S2)
{
if (i.value != ",") S3.Add(i);
}
return S3;
}
}
public class RpnCalc
{
//运算主出口点
public RpnGenerator.Data Calc(List<rpngenerator.item></rpngenerator.item> l)
{
List<rpngenerator.data></rpngenerator.data> result = new List<rpngenerator.data></rpngenerator.data>();
while (l.Count > 0)
{
RpnGenerator.ITEM i = l.First();
l.RemoveAt(0);
if (i.GetType() == typeof(RpnGenerator.Data))
{
result.Add(GetData((RpnGenerator.Data)i));
}
else
{
result.Add(CalcOp((RpnGenerator.Op)i, ref result));
}
}
return result.First();
}
//原子表达式和函数运算,如果有额外的函数,需重载本函数
public virtual RpnGenerator.Data CalcOp(RpnGenerator.Op op, ref List<rpngenerator.data></rpngenerator.data> result)
{
RpnGenerator.Data d = new RpnGenerator.Data("");
switch (op.value)
{
//case RpnGenerator.Op_comma;
case "=": //RpnGenerator.Op_equal.value:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
SetData(rhs1, rhs2);
d.value = "true";
}
break;
//case RpnGenerator.Op_lastOp:
//case RpnGenerator.Op_leftBracket:
case ">": //RpnGenerator.Op_greater:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
int l1;
int l2;
l1 = int.Parse(rhs1.value);
l2 = int.Parse(rhs2.value);
d.value = (l1 > l2).ToString();
}
break;
case ">=": // RpnGenerator.Op_greaterOrEqual:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
int l1;
int l2;
l1 = int.Parse(rhs1.value);
l2 = int.Parse(rhs2.value);
d.value = (l1 >= l2).ToString();
}
break;
case "==": //RpnGenerator.Op_isEqual:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
d.value = (rhs1.value.ToLower().Trim() == rhs2.value.ToLower().Trim()).ToString();
}
break;
case "<": //RpnGenerator.Op_less:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
int l1;
int l2;
l1 = int.Parse(rhs1.value);
l2 = int.Parse(rhs2.value);
d.value = (l1 < l2).ToString();
}
break;
case "<=": // RpnGenerator.Op_lessOrEqual:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
int l1;
int l2;
l1 = int.Parse(rhs1.value);
l2 = int.Parse(rhs2.value);
d.value = (l1 <= l2).ToString();
}
break;
case "&&": //RpnGenerator.Op_logic_and:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
bool l1;
bool l2;
l1 = bool.Parse(rhs1.value);
l2 = bool.Parse(rhs2.value);
d.value = (l1 && l2).ToString();
}
break;
case "!": // RpnGenerator.Op_logic_not:
{
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
bool l1;
l1 = bool.Parse(rhs1.value);
d.value = (!l1).ToString();
}
break;
case "!=": // RpnGenerator.Op_notEqual:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
d.value = (rhs1.value.ToLower().Trim() != rhs2.value.ToLower().Trim()).ToString();
}
break;
case "||": // RpnGenerator.Op_logic_or:
{
RpnGenerator.Data rhs2 = result.Last();
result.RemoveAt(result.Count - 1);
RpnGenerator.Data rhs1 = result.Last();
result.RemoveAt(result.Count - 1);
bool l1;
bool l2;
l1 = bool.Parse(rhs1.value);
l2 = bool.Parse(rhs2.value);
d.value = (l1 || l2).ToString();
}
break;
default:
{
throw new Exception("未处理的运算符或函数 - " + op.value);
}
}
return d;
}
//取值
public virtual RpnGenerator.Data GetData(RpnGenerator.Data d)
{
return d;
}
//赋值
public virtual void SetData(RpnGenerator.Data lhs, RpnGenerator.Data rhs)
{
lhs = rhs;
}
}
}