■ 수식 평가하기

----------------------------------------------------------------------------------------------------


TestProject.zip


MainForm.cs

 

 

using System;

using System.Collections.Generic;

using System.Windows.Forms;

 

namespace TestProject

{

    /// <summary>

    /// 메인 폼

    /// </summary>

    public partial class MainForm : Form

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 우선 순위 - Precedence

 

        /// <summary>

        /// 우선 순위

        /// </summary>

        private enum Precedence

        {

            /// <summary>

            /// NONE

            /// </summary>

            NONE = 11,

 

            /// <summary>

            /// UNARY

            /// </summary>

            /// <remarks>실제로 사용되지 않습니다.</remarks>

            UNARY = 10,

 

            /// <summary>

            /// POWER

            /// </summary>

            /// <remarks>^을 사용하여 지수를 의미한다.</remarks>

            POWER = 9,

 

            /// <summary>

            /// TIMES

            /// </summary>

            TIMES = 8,

 

            /// <summary>

            /// DIV

            /// </summary>

            DIV = 7,

 

            /// <summary>

            /// MODULUS

            /// </summary>

            MODULUS = 6,

 

            /// <summary>

            /// PLUS

            /// </summary>

            PLUS = 5,

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 변수 딕셔너리

        /// </summary>

        private Dictionary<string, string> variableDictionary;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainForm()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainForm()

        {

            InitializeComponent();

 

            #region 이벤트를 설정한다.

 

            this.evaluateButton.Click += evaluateButton_Click;

 

            #endregion

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 평가 버튼 클릭시 처리하기 - evaluateButton_Click(sender, e)

 

        /// <summary>

        /// 평가 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void evaluateButton_Click(object sender, EventArgs e)

        {

            if(this.variableDictionary != null)

            {

                this.variableDictionary.Clear();

            }

            else

            {

                this.variableDictionary = new Dictionary<string,string>();

            }

 

            if(this.name1TextBox.Text.Trim().Length > 0)

            {

                this.variableDictionary.Add(this.name1TextBox.Text.Trim(), this.value1TextBox.Text.Trim());

            }

 

            if(this.name2TextBox.Text.Trim().Length > 0)

            {

                this.variableDictionary.Add(this.name2TextBox.Text.Trim(), this.value2TextBox.Text.Trim());

            }

 

            if(this.name3TextBox.Text.Trim().Length > 0)

            {

                this.variableDictionary.Add(this.name3TextBox.Text.Trim(), this.value3TextBox.Text.Trim());

            }

 

            if(this.name4TextBox.Text.Trim().Length > 0)

            {

                this.variableDictionary.Add(this.name4TextBox.Text.Trim(), this.value4TextBox.Text.Trim());

            }

 

            string expression = this.expressionTextBox.Text.Trim();

 

            this.resultTextBox.Text = string.Empty;

 

            try

            {

                this.resultTextBox.Text = EvaluateExpression(expression).ToString();

            }

            catch(Exception exception)

            {

                MessageBox.Show(this, exception.Message, "에러", MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 수식 평가하기 - EvaluateExpression(source)

 

        /// <summary>

        /// 수식 평가하기

        /// </summary>

        /// <param name="source">소스 문자열</param>

        /// <returns>수식 평가값</returns>

        private double EvaluateExpression(string source)

        {

            int parentCount     = 0;

            int currentPosition = 0;

 

            string expression       = source.Replace(" ", string.Empty);

            int    expressionLength = expression.Length;

 

            if(expressionLength == 0)

            {

                return 0;

            }

 

            bool isUnary = true;

 

            Precedence currentPrecedence = Precedence.NONE;

 

            for(int i = 0; i < expressionLength; i++)

            {

                string character = expression.Substring(i, 1);

 

                bool nextUnary = false;

 

                if(character == " ")

                {

                }

                else if(character == "(")

                {

                    parentCount += 1;

 

                    nextUnary = true;

                }

                else if(character == ")")

                {

                    parentCount -= 1;

 

                    nextUnary = false;

 

                    if(parentCount < 0)

                    {

                        throw new FormatException("닫기 괄호가 너무 많습니다 : '" + source + "'");

                    }

                }

                else if(parentCount == 0)

                {

                    if((character == "^") || (character == "*" ) ||

                       (character == "/") || (character == "\\") ||

                       (character == "%") || (character == "+" ) ||

                       (character == "-"))

                    {

                        nextUnary = true;

 

                        switch(character)

                        {

                            case "^" :

 

                                if(currentPrecedence >= Precedence.POWER)

                                {

                                    currentPrecedence = Precedence.POWER;

                                    currentPosition   = i;

                                }

 

                                break;

 

                            case "*" :

                            case "/" :

 

                                if(currentPrecedence >= Precedence.TIMES)

                                {

                                    currentPrecedence = Precedence.TIMES;

                                    currentPosition   = i;

                                }

 

                                break;

 

                            case "%" :

 

                                if(currentPrecedence >= Precedence.MODULUS)

                                {

                                    currentPrecedence = Precedence.MODULUS;

                                    currentPosition   = i;

                                }

 

                                break;

 

                            case "+" :

                            case "-" :

 

                                if((!isUnary) && currentPrecedence >= Precedence.PLUS)

                                {

                                    currentPrecedence = Precedence.PLUS;

                                    currentPosition   = i;

                                }

 

                                break;

                        }

                    }

                }

 

                isUnary = nextUnary;

            }

 

            if(parentCount != 0)

            {

                throw new FormatException("닫기 괄호가 누락되었습니다 : '" + source + "'");

            }

 

            if(currentPrecedence < Precedence.NONE)

            {

                string expressionLeft  = expression.Substring(0, currentPosition);

                string expressionRight = expression.Substring(currentPosition + 1);

 

                switch(expression.Substring(currentPosition, 1))

                {

                    case "^" : return Math.Pow(EvaluateExpression(expressionLeft), EvaluateExpression(expressionRight));

                    case "*" : return EvaluateExpression(expressionLeft) * EvaluateExpression(expressionRight);

                    case "/" : return EvaluateExpression(expressionLeft) / EvaluateExpression(expressionRight);

                    case "%" : return EvaluateExpression(expressionLeft) % EvaluateExpression(expressionRight);

                    case "+" : return EvaluateExpression(expressionLeft) + EvaluateExpression(expressionRight);

                    case "-" : return EvaluateExpression(expressionLeft) - EvaluateExpression(expressionRight);

                }

            }

 

            if(expression.StartsWith("(") && expression.EndsWith(")"))

            {

                return EvaluateExpression(expression.Substring(1, expressionLength - 2));

            }

 

            if(expression.StartsWith("-"))

            {

                return -EvaluateExpression(expression.Substring(1));

            }

 

            if(expression.StartsWith("+"))

            {

                return EvaluateExpression(expression.Substring(1));

            }

 

            if(expressionLength > 5 && expression.EndsWith(")"))

            {

                int parentPosition = expression.IndexOf("(");

 

                if(parentPosition > 0)

                {

                    string expressionLeft  = expression.Substring(0, parentPosition);

                    string expressionRight = expression.Substring(parentPosition + 1, expressionLength - parentPosition - 2);

 

                    switch(expressionLeft.ToLower())

                    {

                        case "sin"       : return Math.Sin(EvaluateExpression(expressionRight));

                        case "cos"       : return Math.Cos(EvaluateExpression(expressionRight));

                        case "tan"       : return Math.Tan(EvaluateExpression(expressionRight));

                        case "sqrt"      : return Math.Sqrt(EvaluateExpression(expressionRight));

                        case "factorial" : return GetFactorial(EvaluateExpression(expressionRight));

                    }

                }

            }

 

            if(variableDictionary.ContainsKey(expression))

            {

                try

                {

                    return double.Parse(variableDictionary[expression]);

                }

                catch(Exception)

                {

                    throw new FormatException("변수(" + expression + ")가 실수가 아닌 값(" + variableDictionary[expression] +

                        ")을 갖고 있습니다.");

                }

            }

 

            try

            {

                return double.Parse(expression);

            }

            catch(Exception)

            {

                throw new FormatException("수식(" + source + ")을 상수로 평가시 에러가 발생했습니다.");

            }

        }

 

        #endregion

        #region 팩토리얼 구하기 - GetFactorial(value)

 

        /// <summary>

        /// 팩토리얼 구하기

        /// </summary>

        /// <param name="value"></param>

        /// <returns>팩토리얼 값</returns>

        private double GetFactorial(double value)

        {

            if((long)value != value)

            {

                throw new ArgumentException("팩토리얼 함수에 대한 매개 변수는 정수이어야 합니다 : " + value.ToString());

            }

 

            double result = 1;

 

            for(int i = 2; i <= value; i++)

            {

                result *= i;

            }

 

            return result;

        }

 

        #endregion

    }

}

 

----------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker
TAG