C#解析逻辑字符串【x>y&&a>b||p=r】

解析逻辑字符串并动态替换值:"[field]>3&&[field2]<78". field、field2为动态替换值

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    public class ExpressionParser
    {
        #region Fields
        /// <summary>
        /// 将表达式以&&或者||切割
        /// group[1]和group[3]为单个逻辑表达式 group[2]为右边的运算符【&&或||】
        /// </summary>
        private static readonly Regex regCutItem = new Regex(@"(.*?)([&|\|]{2})|(\S.*)");
        /// <summary>
        /// 将每个单独的item匹配出小分子 例子:3>2 => [3,>,2]
        /// </summary>
        private static readonly Regex regCutMolecule = new Regex(@"(.*?)([>|<]=?|=)(.*)");
        /// <summary>
        /// 验证每个单独的item是否合法
        /// </summary>
        private static readonly Regex regValidMolecult = new Regex(@"^([\w\[\]]*?)([>|<]=?|=)([\w\[\]]*)$");
        /// <summary>
        /// 提取表达式中的小括号内容 (如有小括号嵌套 需重复匹配;最先获取最内部括号内容,由内向外获取)
        /// </summary>
        private static readonly Regex regSmallBracket = new Regex(@"\([^(]*?\)");
        /// <summary>
        /// 提取单个单个小分子的字段值
        /// </summary>
        private static readonly Regex regGetField = new Regex(@"^\s*?\[(\S+)\]\s*?$");

        private static readonly string trueText = "1=1";
        private static readonly string falseText = "1=2";
        #endregion

        #region Methods
        /// <summary>
        /// 判断表达式的有效性
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static bool JudgeValid(string expression)
        {
            if (string.IsNullOrEmpty(expression)) new ArgumentException("is null or empty", "expression");
            bool haveBracketite = regSmallBracket.IsMatch(expression);
            //匹配出所有括号内的内容验证是否合法,合法则remove掉
            while (regSmallBracket.IsMatch(expression))
            {
                MatchCollection collection = regSmallBracket.Matches(expression);
                foreach (Match bracketite in collection)
                {
                    int index = 0; string opL = string.Empty, opR = string.Empty;
                    //匹配到的值 带括号(8>5&&7>3.....)
                    string expBracketite = bracketite.Value;
                    index = expression.IndexOf(expBracketite);
                    //括号内容前的连接运算符
                    if (index >= 2) opL = expression.Substring(index - 2, 2);
                    //括号内容后的连接运算符
                    if (expression.Length > index + expBracketite.Length + 2) opR = expression.Substring(index + expBracketite.Length, 2);
                    //如果连接符不为&&或||则不符合表达式规则
                    if (!string.IsNullOrEmpty(opL) && opL != "&&" && opL != "||") return false;
                    if (!string.IsNullOrEmpty(opR) && opR != "&&" && opR != "||") return false;
                    MatchCollection items = regCutItem.Matches(expBracketite.Substring(1, expBracketite.Length - 2));
                    //如果集合数小于1 则括号之间内容为空或者内容不符合规则
                    if (items.Count < 1) return false;
                    int indexOfItem1 = 0;
                    foreach (Match item in items)
                    {
                        indexOfItem1++;
                        //获取表达式
                        string expItem = indexOfItem1 == items.Count ? item.Groups[3].Value : item.Groups[1].Value;
                        //验证表达式的有效性
                        if (!regValidMolecult.IsMatch(expItem)) return false;
                    }
                    //remove括号内的表达式以及括号前的连接运算符
                    expression = expression.Remove(index < 2 ? index : index - 2, expBracketite.Length + (index < 2 ? index : 2));
                }
            }
            //验证去除括号内容后剩下表达式的有效性
            MatchCollection expItems = regCutItem.Matches(expression);
            //如果表达式没有括号且匹配结果数小于1 则表达式内容不符合规则
            if (!haveBracketite && expItems.Count < 1) return false;
            int indexOfItem = 0;
            foreach (Match item in expItems)
            {
                indexOfItem++;
                //获取表达式
                string expItem = indexOfItem == expItems.Count ? item.Groups[3].Value : item.Groups[1].Value;
                //验证表达式的有效性
                if (!regValidMolecult.IsMatch(expItem)) return false;
            }
            return true;
        }

        /// <summary>
        /// 获取表达式结果
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <param name="prm"></param>
        /// <returns></returns>
        public static bool GetResult(string expression, Dictionary<string, object> prm)
        {
            if (!JudgeValid(expression)) throw new Exception("invalid expression");
            //匹配出所有括号内的内容计算结果并根据结果替换对应的值
            while (regSmallBracket.IsMatch(expression))
            {
                MatchCollection collection = regSmallBracket.Matches(expression);
                foreach (Match bracketite in collection)
                {
                    //表达式内容赋值
                    string expBracketite = bracketite.Value;
                    int index = expression.IndexOf(expBracketite);
                    //获取表达式计算后的结果
                    bool result = MosaicLambda(expBracketite.Substring(1, expBracketite.Length - 2), prm);
                    //根据结果将括号内表达式替换成不同字符串
                    expression = expression.Remove(index, expBracketite.Length).Insert(index, result ? trueText : falseText);
                }
            }
            return MosaicLambda(expression, prm);
        }
        /// <summary>
        /// 获取表达式结果
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        static bool GetResult(string expression)
        {
            return GetResult(expression, new Dictionary<string, object>());
        }
        /// <summary>
        /// 拼接动态Lambda并获取结果
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="prm"></param>
        /// <returns></returns>
        static bool MosaicLambda(string expression, Dictionary<string, object> prm)
        {
            //Fields
            Expression lambda = null;
            string connector = null;
            MatchCollection items = regCutItem.Matches(expression);
            int indexOfItem = 0;
            foreach (Match item in items)
            {
                indexOfItem++;
                Expression left = null, right = null;
                BinaryExpression binary = null;
                //获取表达式
                string expItem = indexOfItem == items.Count ? item.Groups[3].Value : item.Groups[1].Value;
                Match Molecule = regCutMolecule.Matches(expItem)[0];
                //判断左边是否是字段
                if (regGetField.IsMatch(Molecule.Groups[1].Value))
                {
                    string field = regGetField.Matches(Molecule.Groups[1].Value)[0].Groups[1].Value;
                    if (!prm.ContainsKey(field)) throw new Exception($"未提供必须字段[{field}]");
                    left = Expression.Constant(prm[field]);
                }
                else
                {
                    object v = null;
                    Type t = TryGetType(Molecule.Groups[1].Value, out v);
                    left = Expression.Constant(v, t);
                }
                //判断右边是否是字段
                if (regGetField.IsMatch(Molecule.Groups[3].Value))
                {
                    string field = regGetField.Matches(Molecule.Groups[3].Value)[0].Groups[1].Value;
                    if (!prm.ContainsKey(field)) throw new Exception($"未提供必须字段[{field}]");
                    right = Expression.Constant(prm[field]);
                }
                else
                {
                    object v = null;
                    Type t = TryGetType(Molecule.Groups[3].Value, out v);
                    right = Expression.Constant(v, t);
                }
                if (left.Type != right.Type) throw new Exception("尝试比较两个不同数据类型的值");
                //根据操作符选择合适的方法进行装载
                switch (Molecule.Groups[2].Value)
                {
                    case ">":
                        binary = Expression.GreaterThan(left, right);
                        break;
                    case ">=":
                        binary = Expression.GreaterThanOrEqual(left, right);
                        break;
                    case "=":
                        binary = Expression.Equal(left, right);
                        break;
                    case "<=":
                        binary = Expression.LessThanOrEqual(left, right);
                        break;
                    case "<":
                        binary = Expression.LessThan(left, right);
                        break;
                    default: throw new Exception("invalid charactor");
                }
                //根据上一个item设置的连接符进行相应的操作
                if (connector == null) lambda = binary;
                else
                {
                    switch (connector)
                    {
                        case "&&":
                            lambda = Expression.And(lambda, binary);
                            break;
                        case "||":
                            lambda = Expression.Or(lambda, binary);
                            break;
                        default: throw new Exception("invalid charactor");
                    }
                }
                //And|Or赋值
                connector = item.Groups[2].Value;
            }
            return Expression.Lambda<Func<bool>>(lambda).Compile().Invoke();
        }

        static Type TryGetType(string v, out object obj)
        {
            int i = default(int); float f = default(float); double d = default(double);
            if (int.TryParse(v, out i)) { obj = i; return typeof(int); }
            if (float.TryParse(v, out f)) { obj = f; return typeof(float); }
            if (double.TryParse(v, out d)) { obj = d; return typeof(double); }
            obj = v;
            return typeof(string);
        }
        #endregion
    }
}

  

posted @ 2017-02-17 15:08  小孑  阅读(775)  评论(0编辑  收藏  举报