للدراسة ، كان من الضروري كتابة محلل للعمليات الحسابية ، والذي لا يمكنه حساب العمليات البسيطة فحسب ، بل أيضًا العمل مع الأقواس والوظائف.
لم أجد حلولًا جاهزة ومناسبة بالنسبة لي على الإنترنت (بعضها كان معقدًا جدًا ، والبعض الآخر لم يكن مرضيًا تمامًا بشروط مهمتي). بعد قليل من الحزن ، بدأت في حل المشكلة بنفسي وأريد الآن مشاركة
كود **** الأصلي مع الحل الأصلي مع العالم.
المشكلة الأولى التي واجهتها هي الأقواس. ليس فقط يجب تنفيذها أولاً ، لذا يمكن أن تكون الأقواس بداخلها. و هكذا.
بالضبط نفس القصة مع الوظائف - في معلمات الوظيفة قد تكون هناك وظائف أخرى وحتى تعبيرات كاملة.

ولكن أكثر على ذلك في وقت لاحق. تحتاج أولاً إلى تحليل التعبير بأكمله. لاحظ أننا قد نواجه إما شريحة أو رقمًا أو معامل (+ ، - ، * ، / ، ^) ، أو دالة ، أو ثابت.
إنشاء قوائم لهذا الشيء كله:
public static List<string> digits = new List<string>() { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "," }; public static List<string> operands = new List<string>() {"^", "/", "*", "+", "-"}; public static List<string> functions = new List<string>() { "sqrt", "sin", "cos", "log", "abs"}; public static List<string> brackets = new List<string>() { "(", ")" }; public static List<string> constants = new List<string>() { "pi" }; public static Dictionary<string, string> constantsValues = new Dictionary<string, string>() { ["pi"] = "3,14159265359" };
ونحن سوف تحقق كل حرف بدوره. بطبيعة الحال ، إذا التقينا علامة "+" أو "-" ليس بعد الرقم ، فإن هذه العلامة تشير إلى الرقم الموجب أو السالب ، على التوالي.
for (int i = 0; i < expression.Length; i++) { if (brackets.Contains(expression[i].ToString())){ if (lastSymbol != ""){ symbols.Add(lastSymbol); lastSymbol = ""; }
في المثال ، تم تخطي الدالة GetParametrs. هناك حاجة للحالات عندما يكون للوظيفة معلمتان. الحقيقة هي أنه لا يمكنك جعل سبليت بسيط. يمكن أن يكون لدينا هذا التعبير:

public static List<string> GetParametrs(string functionParametrs){ int bracketsSum = 0; int functionEnd = 0; for (int j = 0; j < functionParametrs.Length; j++){ if (functionParametrs[j].ToString() == "(") bracketsSum++; if (functionParametrs[j].ToString() == ")") bracketsSum--; if (functionParametrs[j].ToString() == ";" && bracketsSum == 0){ functionEnd = j; break; } } var buffer = new char[functionEnd]; functionParametrs.CopyTo(0, buffer, 0, functionEnd); string firstParametr = new string(buffer); buffer = new char[functionParametrs.Length - functionEnd - 1]; functionParametrs.CopyTo(functionEnd + 1, buffer, 0, functionParametrs.Length - functionEnd - 1); string secondParametr = new string(buffer); return ( new List<string>() { firstParametr, secondParametr } ); }
لذلك ، يتم تقسيم التعبير إلى قيم أصغر ، بالإضافة إلى ذلك ، يتم حساب قيم الوظائف بالفعل واستبدالها في التعبير الرئيسي كأرقام.
يمكن معالجة الأقواس وفقًا لنفس المبدأ - احسبها على الفور واستبدلها بالأرقام:
while (symbols.Contains("(")) { int bracketsStart = 0; int bracketsEnd = 0; int bracketsSum = 0; for (int i = 0; i < symbols.Count; i++) { if (symbols[i] == "(") { bracketsStart = i; bracketsSum = 1; break; } } for (int i = bracketsStart + 1; i < symbols.Count; i++) { if (symbols[i] == "(") bracketsSum++; if (symbols[i] == ")") bracketsSum--; if (bracketsSum == 0) { bracketsEnd = i; break; } } string bracketsExpression = ""; for (int i = bracketsStart + 1; i < bracketsEnd; i++) bracketsExpression += symbols[i]; symbols[bracketsStart] = CalculateExpression(bracketsExpression).ToString(); symbols.RemoveRange(bracketsStart + 1, bracketsEnd - bracketsStart); }
العثور على مؤشر قوس إغلاق مرة أخرى أكثر تعقيدًا قليلاً. لا يمكنك فقط أخذ شريحة الإغلاق التالية. هذا لن يعمل مع الأقواس المتداخلة.
الجزء الرئيسي من البرنامج مكتوب. يبقى لتنفيذ حساب التعبيرات الحسابية العادية. حتى لا تقلق بشأن ترتيب الإجراءات ، قررت أن أكتب التعبير باللغة الإنجليزية:
foreach(var j in operands){
وأخيراً ، مع المكدس ، نحسب قيمة التعبير:
List<string> result = new List<string>(); string[] temp = symbols[0].Split(' '); for (int i = 0; i < temp.Length; i++) { if (operands.Contains(temp[i])) { if (temp[i] == "^") { result[result.Count - 2] = Math.Pow(double.Parse(result[result.Count - 2]), double.Parse(result[result.Count - 1])).ToString(); result.RemoveRange(result.Count - 1, 1); } if (temp[i] == "+") { result[result.Count - 2] = (double.Parse(result[result.Count - 2]) + double.Parse(result[result.Count - 1])).ToString(); result.RemoveRange(result.Count - 1, 1); } if (temp[i] == "-") { result[result.Count - 2] = (double.Parse(result[result.Count - 2]) - double.Parse(result[result.Count - 1])).ToString(); result.RemoveRange(result.Count - 1, 1); } if (temp[i] == "*") { result[result.Count - 2] = (double.Parse(result[result.Count - 2]) * double.Parse(result[result.Count - 1])).ToString(); result.RemoveRange(result.Count - 1, 1); } if (temp[i] == "/") { result[result.Count - 2] = (double.Parse(result[result.Count - 2]) / double.Parse(result[result.Count - 1])).ToString(); result.RemoveRange(result.Count - 1, 1); } } else result.Add(temp[i]); }
إذا سارت الأمور على ما يرام ، فستكون النتيجة في النتيجة [0].
→ تصل إلى جيثب مع رمز كامل