逆波兰表达式
大石头 authored at 2017-06-10 00:00:45
5.78 KiB
X
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace NewLife.Expressions
{
    /// <summary>与或非表达式</summary>
    public class UnionExpresion : RpnExpression
    {
        /// <summary>位与</summary>
        public static readonly Char AndChar = '&';
        /// <summary>位或</summary>
        public static readonly Char OrChar = '|';

        /// <summary>实例化</summary>
        public UnionExpresion()
        {
            OperationChars = new Char[] { OrChar, AndChar, LeftBracket, RightBracket };
        }

        /// <summary>操作符等级</summary>
        /// <param name="op"></param>
        /// <returns></returns>
        public override Int32 GetOperationLevel(String op)
        {
            switch (op)
            {
                case "|":
                case "&":
                    return 1;
                case "(":
                case ")":
                    return 0;
                default:
                    return -1;
            }
        }

        /// <summary>适配替换</summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        protected override String AdapteAndReplace(String expression)
        {
            if (String.IsNullOrWhiteSpace(expression)) return String.Empty;

            return expression.ToUpper().Replace("AND", AndChar.ToString()).Replace("OR", OrChar.ToString()).Replace(EmptyChar.ToString(), String.Empty);
        }

        /// <summary>容器</summary>
        IList<IndexInfoResult> Container { get; set; }

        /// <summary>解逆波兰表达式</summary>
        /// <param name="expression">标准逆波兰表达式</param>
        /// <param name="args"></param>
        /// <returns>逆波兰表达式的解</returns>
        public override Object Complie(String expression, params Object[] args)
        {
            if (String.IsNullOrWhiteSpace(expression)) return null;

            var arr = expression.Split(new Char[] { JoinChar });

            var codes = new Stack<IndexInfoResult>();

            Container = Container ?? new List<IndexInfoResult>();

            for (var i = 0; i < arr.Length; i++)
            {
                var level = GetOperationLevel(arr[i]);
                if (level < 0)
                {
                    var condition = arr[i].Trim();

                    var result = Container.FirstOrDefault(p => String.Equals(p.Mark, condition));
                    if (result == null) throw new ArgumentNullException(condition);

                    codes.Push(result);
                }
                else if (level > 0)
                {
                    // 为符号则将数字堆栈后两个数据解压并计算,将计算结果压入堆栈
                    if (codes.Count > 1)
                    {
                        var lastValue = codes.Pop();
                        var firstValue = codes.Pop();
                        var result = ComplieRpnExp(firstValue.IndexInfos.Select(p => p.StockCode), lastValue.IndexInfos.Select(p => p.StockCode), arr[i]);

                        var infoResult = new IndexInfoResult("(" + firstValue.Mark + arr[i].Replace("&", " AND ").Replace("|", " OR ") + lastValue.Mark + ")");

                        foreach (var code in result)
                        {
                            infoResult.IndexInfos.Add(new IndexInfo(code));
                        }

                        // 压入计算结果
                        codes.Push(infoResult);
                    }
                }
            }

            return codes.Pop();
        }

        /// <summary>是否有效</summary>
        /// <param name="arr"></param>
        /// <returns></returns>
        public override Boolean IsValid(String[] arr)
        {
            if (arr == null || arr.Length == 0) return false;

            var regex = new Regex(@"^#\d+$");
            for (var i = 0; i < arr.Length; i++)
            {
                if (!regex.IsMatch(arr[i].Trim())) throw new ArgumentException("错误数值:" + arr[i] + ".");
            }

            return true;
        }

        /// <summary>所有掩码</summary>
        /// <returns></returns>
        public IEnumerable<String> GetAllMarks()
        {
            if (String.IsNullOrWhiteSpace(Value)) yield return null;

            var regex = new Regex(@"#\d+");
            var collections = regex.Matches(AdapteAndReplace(Value));

            foreach (Match match in collections)
            {
                yield return match.Groups[0].Value;
            }
        }

        private IEnumerable<String> ComplieRpnExp(IEnumerable<String> firstValue,
            IEnumerable<String> lastValue, String operation)
        {
            if (String.IsNullOrWhiteSpace(operation)) return new List<String>();

            if (String.Equals(operation.Trim(), AndChar.ToString())) return GetAndResult(firstValue, lastValue);

            if (String.Equals(operation.Trim(), OrChar.ToString())) return GetOrResult(firstValue, lastValue);

            return new List<String>();
        }

        private IEnumerable<String> GetOrResult(IEnumerable<String> firstValue, IEnumerable<String> lastValue)
        {
            if (firstValue == null) return lastValue ?? new List<String>();

            if (lastValue == null) return firstValue ?? new List<String>();

            return firstValue.Union(lastValue);
        }

        private IEnumerable<String> GetAndResult(IEnumerable<String> firstValue, IEnumerable<String> lastValue)
        {
            if (firstValue == null || lastValue == null) return new List<String>();

            return firstValue.Intersect(lastValue);
        }
    }
}