引入redis服务,支持自动化单元测试
大石头 编写于 2022-03-31 22:56:30
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 UnionExpresion() => OperationChars = new Char[] { '|', '&', '(', ')' };

        /// <summary>操作符等级</summary>
        /// <param name="op"></param>
        /// <returns></returns>
        public override Int32 GetOperationLevel(String op)
        {
            return op switch
            {
                "|" or "&" => 1,
                "(" or ")" => 0,
                _ => -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", "&").Replace("OR", "|").Replace(" ", 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 (expression == null || expression.Length == 0) return 0;

            var arr = expression;

            var codes = new Stack<IndexInfoResult>();

            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(), "&")) return GetAndResult(firstValue, lastValue);

            if (String.Equals(operation.Trim(), "|")) 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);
        }
    }
}