using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using UnityEngine; public class Equation : Singleton { public static readonly List operatorList = new List() { '*', '-', '+', '/', '^', '!', '@', '%', ';', '#', '$', '~', '&' }; public static StringBuilder textBuilder = new StringBuilder(); private List> keyValueDic = new List>(); public readonly Regex replaecRegex = new Regex(@"[a-zA-Z]{2,50}"); public T Eval(string equation) where T : struct { keyValueDic.Sort(Compare); equation = GetEquation(equation); T val = default(T); try { EquationParse equationParse = new EquationParse(equation); val = (T)Convert.ChangeType(equationParse.result, typeof(T)); equationParse = null; } catch (Exception e) { Debug.LogError(e.Message); } return val; } private string GetEquation(string equation) { try { MatchCollection matchArray = replaecRegex.Matches(equation); textBuilder.Length = 0; int length = 0; if (matchArray != null) { for (int i = 0; i < matchArray.Count; i++) { Match match = matchArray[i]; textBuilder.Append(equation.Substring(length, match.Index - length)); length = match.Index + match.Length; bool _replace = false; for (int j = 0; j < keyValueDic.Count; j++) { if (match.Value.Equals(keyValueDic[j].Key)) { textBuilder.Append(keyValueDic[j].Value); _replace = true; break; } } if (!_replace) { textBuilder.Append(0); } } } textBuilder.Append(equation.Substring(length, equation.Length - length)); } catch (Exception e) { Debug.Log(e.Message); } return textBuilder.ToString(); } public void AddKeyValue(string key, object val) { int index = keyValueDic.FindIndex((x) => { return x.Key == key; }); if (index == -1) { KeyValuePair keyValuePair = new KeyValuePair(key, val.ToString()); keyValueDic.Add(keyValuePair); } } public void Clear() { keyValueDic.Clear(); } int Compare(KeyValuePair x, KeyValuePair y) { return -x.Key.Length.CompareTo(y.Key.Length); } public class EquationParse { public string equation { get; private set; } public string result { get; private set; } private StringBuilder equationBuilder = new StringBuilder(); private List subEquations = new List(); private List operatorTypeList = new List(); private List values = new List(); public EquationParse(string _equation) { this.equation = _equation; this.result = string.Empty; equationBuilder.Length = 0; if (CheckSplit()) { return; } Subsection(); GetResult(); } private bool CheckSplit() { var _left = string.Empty; var _right = string.Empty; OperatorType _operatorType; if (Split(equation, out _left, out _right, out _operatorType)) { var _leftResult = new EquationParse(_left); var _rightResult = new EquationParse(_right); result = GetResult(_leftResult.result, _rightResult.result, _operatorType).ToString(); return true; } return false; } private void Subsection() { try { int bracketCnt = 0; int startIndex = 0; int length = 0; int index = 0; for (int i = 0; i < equation.Length; i++) { if (equation[i] == '(') { i = i + 1; startIndex = i; while (i < equation.Length && (equation[i] != ')' || bracketCnt > 0)) { if (equation[i] == '(') { bracketCnt++; } else if (equation[i] == ')') { bracketCnt--; } length++; i = i + 1; } subEquations.Add(new EquationParse(equation.Substring(startIndex, length))); length = 0; equationBuilder.Append('='); equationBuilder.Append(index); equationBuilder.Append('='); index++; continue; } equationBuilder.Append(equation[i]); } } catch (Exception e) { Debug.Log(e.Message); } } private void AnalysisEquation() { try { textBuilder.Length = 0; for (int i = 0; i < subEquations.Count; i++) { equationBuilder.Replace(string.Format("={0}=", i), subEquations[i].result); subEquations[i] = null; } subEquations.Clear(); var _result = equationBuilder.ToString(); char _lastChar = default(char); for (int i = 0; i < _result.Length; i++) { if (i - 1 > 0 && _result[i - 1] == 'E') {//过滤超大数值后的符号 textBuilder.Append(_result[i]); continue; } int index = operatorList.IndexOf(_result[i]); if (index != -1 && _lastChar >= '0' && _lastChar <= '9') { values.Add(textBuilder.ToString()); textBuilder.Length = 0; operatorTypeList.Add(GetOperatorType(_result[i])); } else { textBuilder.Append(_result[i]); } _lastChar = _result[i]; } values.Add(textBuilder.ToString()); } catch (Exception e) { Debug.Log(e.Message); } } public void GetResult() { AnalysisEquation(); try { for (int i = 0; i < operatorTypeList.Count; i++) { if (IsPriorityOperator(operatorTypeList[i])) { double _result = 0; if (IsUnaryOperator(operatorTypeList[i])) { _result = GetResult(values[i], string.Empty, operatorTypeList[i]); } else { _result = GetResult(values[i], values[i + 1], operatorTypeList[i]); values.RemoveAt(i); } values.RemoveAt(i); values.Insert(i, _result.ToString()); operatorTypeList.RemoveAt(i); i--; } } while (values.Count > 1 && operatorTypeList.Count > 0) { double _result = 0; if (IsUnaryOperator(operatorTypeList[0])) { _result = GetResult(values[0], string.Empty, operatorTypeList[0]); } else { _result = GetResult(values[0], values[1], operatorTypeList[0]); values.RemoveAt(0); } values.RemoveAt(0); values.Insert(0, _result.ToString()); operatorTypeList.RemoveAt(0); } if (operatorTypeList.Count == 1 && IsUnaryOperator(operatorTypeList[0])) { result = GetResult(values[0], string.Empty, operatorTypeList[0]).ToString(); } else { result = values[0]; } } catch (Exception e) { Debug.Log(e.Message); } } public static double GetResult(string leftValue, string rightValue, OperatorType operatorType) { double _leftValue = 0, _rightValue = 0; try { double.TryParse(leftValue, out _leftValue); double.TryParse(rightValue, out _rightValue); } catch (Exception) { Debug.LogErrorFormat("字符串不能转为数值{0} {1}", leftValue, rightValue); } switch (operatorType) { case OperatorType.Plus: return _leftValue + _rightValue; case OperatorType.Subtract: return _leftValue - _rightValue; case OperatorType.Ride: return _leftValue * _rightValue; case OperatorType.Divide: if (_rightValue == 0) { _rightValue = 1; } return _leftValue / _rightValue; case OperatorType.Pow: return Math.Pow(_leftValue, _rightValue); case OperatorType.Min: return Math.Min(_leftValue, _rightValue); case OperatorType.Max: return Math.Max(_leftValue, _rightValue); case OperatorType.Remain: return _leftValue % _rightValue; case OperatorType.Random: { return UnityEngine.Random.Range((float)_leftValue, (float)_rightValue); } case OperatorType.Floor: return Math.Floor(_leftValue); case OperatorType.Ceil: return Math.Ceiling((float)_leftValue); case OperatorType.RandomInt: { return UnityEngine.Random.Range((int)_leftValue, (int)_rightValue); } case OperatorType.Sqrt: return Math.Sqrt(_leftValue); } return 0; } public static OperatorType GetOperatorType(char _operator) { switch (_operator) { case '+': return OperatorType.Plus; case '-': return OperatorType.Subtract; case '*': return OperatorType.Ride; case '/': return OperatorType.Divide; case '^': return OperatorType.Pow; case '!': return OperatorType.Min; case '@': return OperatorType.Max; case '%': return OperatorType.Remain; case ';': return OperatorType.Random; case '#': return OperatorType.Floor; case '$': return OperatorType.Ceil; case '~': return OperatorType.RandomInt; case '&': return OperatorType.Sqrt; } return OperatorType.Plus; } public static bool IsPriorityOperator(OperatorType operatorType) { if (operatorType == OperatorType.Plus || operatorType == OperatorType.Subtract) { return false; } return true; } public static bool IsUnaryOperator(OperatorType operatorType) { if (operatorType == OperatorType.Floor || operatorType == OperatorType.Ceil || operatorType == OperatorType.Sqrt) { return true; } return false; } private static bool Split(string _source, out string _left, out string _right, out OperatorType _type) { _left = _right = string.Empty; _type = OperatorType.Plus; try { var _index = 0; for (int i = _source.Length - 1; i >= 0; i--) { if (_source[i] == ')') { _index++; continue; } else if (_source[i] == '(') { _index--; continue; } if (IsSplitOperator(_source[i], out _type) && _index == 0) { _left = _source.Substring(0, i); if (i + 1 < _source.Length) { _right = _source.Substring(i + 1); } return true; } } } catch (Exception e) { Debug.Log(e.Message); } return false; } public static bool IsSplitOperator(char _char, out OperatorType _type) { var _index = operatorList.FindIndex((x) => { return x == _char; }); _type = OperatorType.Plus; if (_index == -1) { return false; } _type = GetOperatorType(_char); switch (_type) { case OperatorType.Floor: case OperatorType.Ceil: case OperatorType.Min: case OperatorType.Max: case OperatorType.Remain: case OperatorType.Pow: case OperatorType.Random: case OperatorType.RandomInt: case OperatorType.Sqrt: return true; } return false; } } public enum OperatorType { Plus,//+ Subtract,//- Ride,//* Divide,// / Pow,// ^ Min,// ! Max,// @ Remain,// % Random, Floor, Ceil, RandomInt, Sqrt } }