using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.Text;
|
using System.Text.RegularExpressions;
|
using UnityEngine;
|
|
|
public class Equation : Singleton<Equation>
|
{
|
public static readonly List<char> operatorList = new List<char>() { '*', '-', '+', '/', '^', '!', '@', '%', ';', '#', '$', '~', '&' };
|
|
public static StringBuilder textBuilder = new StringBuilder();
|
|
private List<KeyValuePair<string, string>> keyValueDic = new List<KeyValuePair<string, string>>();
|
|
public readonly Regex replaecRegex = new Regex(@"[a-zA-Z]{2,50}");
|
|
public T Eval<T>(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<string, string> keyValuePair = new KeyValuePair<string, string>(key, val.ToString());
|
keyValueDic.Add(keyValuePair);
|
}
|
}
|
|
public void Clear()
|
{
|
keyValueDic.Clear();
|
}
|
|
int Compare(KeyValuePair<string, string> x, KeyValuePair<string, string> 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<EquationParse> subEquations = new List<EquationParse>();
|
private List<OperatorType> operatorTypeList = new List<OperatorType>();
|
private List<string> values = new List<string>();
|
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
|
}
|
}
|