表达式计算

来源:互联网 发布:伴奏软件免费下载 编辑:程序博客网 时间:2024/05/21 06:02

自定义表达式解析,涉及到三个主要步骤:
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 &gt;= cur.Length && op.value.Substring(0, cur.Length) == cur) leftMatchCnt++;                    if (cur.Length &gt;= 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 &gt; 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 &gt; 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 &gt; 0)                    {                        l.Add(d);                    }                    leftMatchCnt = 0;                    if (cur.Length &gt; 0) goto RECHECK;                }                else if (oldLeftMatchCnt &gt; 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 &gt; 0)                {                    l.Add(d);                }            }            return l;        }    }    /// <summary>    /// 中序-&gt;逆波兰转换    /// 本模块的输入是结构化处理过的表达式,其基本元素是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("&gt;", 2, 16);        static public Op Op_greaterOrEqual = new Op("&gt;=", 2, 16);        static public Op Op_less = new Op("&lt;", 2, 16);        static public Op Op_lessOrEqual = new Op("&lt;=", 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 &gt; S1.Peek().priority) S1.Push(io);                        else                        {                            while (S1.Peek().priority &gt;= 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 &gt; 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 &gt; 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 "&gt;": //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 &gt; l2).ToString();                    }                    break;                case "&gt;=": // 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 &gt;= 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 "&lt;": //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 &lt; l2).ToString();                    }                    break;                case "&lt;=": // 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 &lt;= 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;        }    }}
原创粉丝点击