## 一:背景 ### 1. 講故事 前段時間有個朋友找到我,說他們的程式有偶發崩潰的情況,讓我幫忙看下怎麼回事,針對這種 crash 的程式,用 AEDebug 的方式抓取一個便知,有了 dump 之後接下來就可以分析了。 ## 二:Windbg 分析 ### 1. 為什麼會崩潰 既然是程式的崩潰 ...
實現語言:C#
思路:
1.括弧裡面的計算優先順序最高,首先計算出括弧裡面的值;
2.將所有的括弧值計算完成後,將得到不包含括弧的數學算式A;
3.數學算式A按先乘除後加減的優先順序計算處結果。
使用單的技術:
在解析數據算式過程中使用棧結構,可以比較方便比配左右括弧。
/// <summary>
/// 計算表達式的值
/// 例子:3/3-[(1/2)+(2*3)]*(1+2)*100+100
/// </summary>
/// <param name="expressionInput"></param>
/// <returns></returns>
public static decimal CalculateExpression(this string expressionInput)
{
try
{
string expression = expressionInput.RemoveNewLineAndSpace();
Stack<char> stack = new Stack<char>(1000);
List<char> startChars = new List<char>(4) { '(', '[', '{' };
List<char> endChars = new List<char>(4) { ')', ']', '}' };
foreach (char item in expression)
{
if (!endChars.Contains(item))
{
stack.Push(item);
continue;
}
StringBuilder childExpression = new StringBuilder();
while (true)
{
if (stack.Count < 1) break;
char expressionContent = stack.Pop();
if (startChars.Contains(expressionContent)) break;
childExpression.Insert(0, expressionContent);
}
decimal tempResult = CalculateSimpleExpression(childExpression.ToString());
//Replace("-","|") 處理負數運算
tempResult.ToString().Replace("-", "|").ToCharArray().ToList().ForEach(c => stack.Push(c));
}
StringBuilder simpleExpression = new StringBuilder();
while (stack.Count > 0)
{
simpleExpression.Insert(0, stack.Pop());
}
return CalculateSimpleExpression(simpleExpression.ToString());
}
catch
{
throw new Exception("計算表達式的值報錯");
}
}
/// <summary>
/// 計算簡單表達式的值
/// 不能包含括弧
/// </summary>
/// <param name="exp"></param>
/// <returns></returns>
private static decimal CalculateSimpleExpression(string exp)
{
if (decimal.TryParse(exp, out decimal r))
{
return r;
}
if (exp.StartsWith("-") || exp.StartsWith("+"))
{
exp = $"0{exp}";
}
List<char> operateCodes = new List<char>(4) { '+', '-', '*', '/' };
List<string> items = new List<string>();
StringBuilder itemStr = new StringBuilder();
exp.ToArray().ToList().ForEach(item => {
if (!operateCodes.Contains(item))
{
itemStr.Append(item);
return;
}
items.Add(itemStr.ToString().Replace("|", "-"));//Replace("-","|") 處理負數運算
items.Add(item.ToString());
itemStr.Clear();
});
items.Add(itemStr.ToString().Replace("|", "-"));
// originalValues:原始項 operates:操作符
Func<List<string>, List<string>, Stack<string>> CalExpression = (originalValues, operates) =>
{
Stack<string> calculatingExpression = new Stack<string>(16);
foreach (string item in originalValues)
{
bool existOperateCode = operates.Count(c => calculatingExpression.Contains(c)) > 0 ? true : false;
if (existOperateCode == false)
{
calculatingExpression.Push(item);
continue;
}
var cal = new Dictionary<string, Func<decimal, decimal, decimal>>();
cal.Add("*", (a, b) => a * b);
cal.Add("/", (a, b) => a / b);
cal.Add("+", (a, b) => a + b);
cal.Add("-", (a, b) => a - b);
decimal tempValue = cal[calculatingExpression.Pop()](decimal.Parse(calculatingExpression.Pop()), decimal.Parse(item));
calculatingExpression.Push(tempValue.ToString());
}
return calculatingExpression;
};
//先計算乘除
items = CalExpression(items, new List<string>() { "*", "/" }).ToList();
items.Reverse();
//先計算加減
var resultStack = CalExpression(items, new List<string>() { "+", "-" });
return decimal.Parse(resultStack.Pop());
}
驗證:
"3/3-[(1/2)+(2*3)]*(1+2)*100+100".CalculateExpression();
結果:-1849