可自定义函数、并且函数可任意嵌套的中缀表达式解析器

中缀表达式解析器的特点:
- 可自定义函数、并且函数可任意嵌套的中缀表达式转化成声明函数参数个数的后缀表达式
- 支持算术运算和逻辑运算
- {}用来表示优先级,()用来标识自定义函数的参数列表

示例:
中缀表达式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;
        }
    }

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* 表达式计算 */ /* 调用方式:CalcExp('1+max(0.5,sin(1))+sum(1,2^3,mod(5,3))', res, infoStr) */ /* 带符号参数调用方法,先调用符号定义AddSignParam,再调用 CalcExp: */ /* AddSignParam(['a','s'], [1, 0.5]); 或者 AddSignParam('a=1,s=0.5') */ /* CalcExp('1+a+sin(s)', res, infoStr) */ /* 其中res存储计算结果,为double型;infoStr存储计算时的提示信息,为string */ 表达式计算器 V2.3 支持以下功能: 1、四则运算 + - * / 、括弧()、正负(+ -) 2、百分数 %、求幂 ^ 、整数阶乘 ! (1 至 150) 3、参数符号计算,示例:a+b @@a=1,b=2 结算结果为3 用@@表示表达式中定义符号的值 4、常数e、圆周率PI 5、丰富的函数功能: 统计函数: max,min,sum,avg,stddev 标准偏差,均支持多参数 三角函数: sin,cos,tan,arcsin,arccos,arctan degrad(60) 角度转弧度 raddeg(3.14) 弧度转角度 costh(a,b,c) 余弦定理 cosC) 指数对数函数:sqrt,power(x,y),abs,exp,log2,log10,logN(a,N),ln 数据处理函数:int(x),trunc(x) 取整 frac(x) 取小数部分 round(x) 四舍五入取整 roundto(x,-1) 保留一位小数 mod(M,N) 求模 几何面积函数:s_tria(a,b,c) 三角形面积 s_circ(r) 圆形面积 s_elli(a,b) 椭圆面积 s_rect(a,b) 矩形面积 s_poly(a,n) 正多边形面积 平面几何函数:pdisplanes(x1,y1,x2,y2) 平面两点距离 pdisspace(x1,y1,z1,x2,y2,z2) 空间两点 p_line(x0,y0, A, B, C) 平面点到线距离 p_planes(x0,y0,z0 A, B, C, D)空间点到面距离 数列求和: sn(a1, d, n) 等差数列前n项和 sqn(a1, q, n) 等比数列前n项和 个税计算函数:intax(x), arcintax(x) 个税反算 6 、历史计算记录,双击计算记录可重新修改计算 示例: sin(1)+(-2+(3-4))*20% , e^63+PI , 15! , log2(max(2,3)) 注: 运算符必须为半角格式,三角函为弧度,输入可用空格间隔

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值