CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 2 FirstFirst 12
Results 16 to 22 of 22
  1. #16
    Join Date
    Apr 2009
    Posts
    1,355

    Re: can i convert a string into a math expression?

    i'm sorry i was out of network.
    i'm sorry to both, but i never worked with tokers and i must learn how to use them(i must go from the start).
    but i can share these code that now works with minus too:
    Code:
    class MathOperators{
        public:
    
    
        enum enumMathOperators
        {
            ParenthesesOpen='(',
            ParenthesesClose=')',
            Add='+',
            Minus='-',
            Multiplication ='*',
            Space=' ',
            Division ='/'
        };
    
    
        static bool IsMathOperator(char enMath)
        {
            switch(enMath)
            {
                case ParenthesesOpen:
                case ParenthesesClose:
                case Add:
                case Minus:
                case Multiplication:
                case Space:
                case Division:
                    return true;
                default:
                    return false;
            }
        }
    };
    
    
    
    
    
    
    bool IsNumeric(string strValue)
    {
        for(unsigned int i=0; i<strValue.size() ; i++)
        {
            if(!isdigit(strValue[i]))
                return false;
        }
        return true;
    }
    
    
    void CalculateExpression(string strMathExpression)
    {
        //clean empty spaces
        for(unsigned int i=0; i<strMathExpression.size(); i++)
        {
            if(strMathExpression[i]== ' ' || strMathExpression[i]== '\t')
            {
                strMathExpression.erase(i,1);
                i=0;
            }
        }
    
    
        //spare the operator and numbers
        //for add them on a vector:
        string strNumber="";
        vector<string> vecOperator;
        int OperatorCount=0;
    
    
        //we must add a null string terminator
        //for we convert the char to string
        //or we can get unexpected results:
        char chr[]={'0','\0'};
        for(unsigned int i=0; i<=strMathExpression.size() ; i++)
        {
            chr[0]=strMathExpression[i];
            if((chr[0]=='-' && strMathExpression[i-1]=='-'))
            {
                vecOperator[vecOperator.size()-1]='+';
                OperatorCount++;
    
    
                continue;
            }
            else if((chr[0]=='-' && strMathExpression[i-1]=='+'))
            {
                vecOperator[vecOperator.size()-1]='-';
                OperatorCount++;
    
    
                continue;
            }
            else if((chr[0]=='+' && strMathExpression[i-1]=='-'))
            {
                vecOperator[vecOperator.size()-1]='-';
                OperatorCount++;
    
    
                continue;
            }
            else if((chr[0]=='+' && strMathExpression[i-1]=='+'))
            {
                vecOperator[vecOperator.size()-1]='+';
                OperatorCount++;
    
    
                continue;
            }
            if(isdigit(chr[0]) || chr[0]=='.')
            {
                strNumber+=chr[0];
            }
            else
            {
                if(isdigit(strNumber[0]))
                    vecOperator.push_back(strNumber);
                if( MathOperators::IsMathOperator(chr[0])==true)
                {
                    vecOperator.push_back(chr);
                    OperatorCount++;
                }
                OperatorCount++;
                strNumber="";
    
    
            }
        }
    
    
        //print actual vector:
        for (unsigned int a=0; a<vecOperator.size();a++)
        {
            cout << vecOperator[a] << " ";
        }
        cout << "\n";
    
    
        //making the math:
        for(unsigned int i=0;i<vecOperator.size(); i++)
        {
            double result=0.0f;
            //test the math order:
            for(unsigned int a=0;a<vecOperator.size(); a++)
            {
                if(vecOperator[a]=="*" || vecOperator[a]=="/" )
                {
                    i=a;
                    break;
                }
            }
    
    
            if(vecOperator[i]=="+")
            {
                //get result in int:
                result=stof(vecOperator[i-1])+ stof(vecOperator[i+1]);
    
    
                string strResult=to_string(result);
    
    
                //erase all zeros after the dot
                //if the dot don't show any zero, is deleted too:
                for(unsigned int intResult=(strResult.size()-1); intResult>0; --intResult)
                {
                    if(strResult[intResult]=='0' && strResult[intResult-1]=='.')
                    {
                        strResult.erase(intResult,1);
                        //strResult.erase(intResult-1,1);
                        strResult[intResult-1]='\0';
                        break;
                    }
                    else if(strResult[intResult]=='0')
                    {
                        //strResult.erase(intResult,1);
                        strResult[intResult]='\0';
                    }
                    else
                    {
                        break;
                    }
                }
                //get the result in int to string:
                vecOperator[i-1]= strResult;
    
    
                //erase the next 2 elements:
                vecOperator.erase(vecOperator.begin()+i,vecOperator.begin()+i+2);
    
    
                //print the elements after changes:
                for (unsigned int a=0; a<vecOperator.size();a++)
                {
                    cout << vecOperator[a] << " ";
                }
                cout << "\n";
    
    
                //before continue the i must be -1
                //when the for restart, the i will be 0:
                i=-1;
                continue;
            }
    
    
            else if(vecOperator[i]=="-")
            {
                result=stof(vecOperator[i-1])- stof(vecOperator[i+1]);
                string strResult=to_string(result);
                for(unsigned int intResult=(strResult.size()-1); intResult>0; --intResult)
                {
                    if(strResult[intResult]=='0' && strResult[intResult-1]=='.')
                    {
                        strResult.erase(intResult,1);
                        strResult.erase(intResult-1,1);
                        break;
                    }
                    else if(strResult[intResult]=='0')
                    {
                        strResult.erase(intResult,1);
                    }
                    else
                    {
                        break;
                    }
                }
                //get the result in int to string:
                vecOperator[i-1]= strResult;
                vecOperator.erase(vecOperator.begin()+i,vecOperator.begin()+i+2);
                for (unsigned int a=0; a<vecOperator.size();a++)
                {
                    cout << vecOperator[a] << " ";
                }
                cout << "\n";
                i=-1;
                continue;
            }
            else if(vecOperator[i]=="/")
            {
                result=stof(vecOperator[i-1])/ stof(vecOperator[i+1]);
                string strResult=to_string(result);
                for(unsigned int intResult=(strResult.size()-1); intResult>0; --intResult)
                {
                    if(strResult[intResult]=='0' && strResult[intResult-1]=='.')
                    {
                        strResult.erase(intResult,1);
                        strResult.erase(intResult-1,1);
                        break;
                    }
                    else if(strResult[intResult]=='0')
                    {
                        strResult.erase(intResult,1);
                    }
                    else
                    {
                        break;
                    }
                }
                //get the result in int to string:
                vecOperator[i-1]= strResult;
                vecOperator.erase(vecOperator.begin()+i,vecOperator.begin()+i+2);
                for (unsigned int a=0; a<vecOperator.size();a++)
                {
                    cout << vecOperator[a] << " ";
                }
                cout << "\n";
                i=-1;
                continue;
            }
            else if(vecOperator[i]=="*")
            {
                result=stof(vecOperator[i-1])* stof(vecOperator[i+1]);
                string strResult=to_string(result);
                for(unsigned int intResult=(strResult.size()-1); intResult>0; --intResult)
                {
                    if(strResult[intResult]=='0' && strResult[intResult-1]=='.')
                    {
                        strResult.erase(intResult,1);
                        strResult.erase(intResult-1,1);
                        break;
                    }
                    else if(strResult[intResult]=='0')
                    {
                        strResult.erase(intResult,1);
                    }
                    else
                    {
                        break;
                    }
                }
                //get the result in int to string:
                vecOperator[i-1]= strResult;
                vecOperator.erase(vecOperator.begin()+i,vecOperator.begin()+i+2);
                for (unsigned int a=0; a<vecOperator.size();a++)
                {
                    cout << vecOperator[a] << " ";
                }
                cout << "\n";
                i=-1;
                continue;
            }
        }
    }
    these is the basic of basic for what we can do for convert 1 string to Math Expression.
    my code is limited, because don't test the errors.
    if i add: 4-5+6--7(isn't so good adding minus without parentheses, but it's ok for now).
    heres the print:
    4 - 5 + 6 + 7
    -1 + 6 + 7
    5 + 7
    12

    yes you have another question: why that big empty space between '5' and '+'!?! i'm sorry, for now, i don't know why.
    but works...
    see the next:
    3+5-6*7+8-9*2
    output:
    3 + 5 - 6 * 7 + 8 - 9 * 2
    3 + 5 - 42 + 8 - 9 * 2
    3 + 5 - 42 + 8 - 18
    8 - 42 + 8 - 18
    -34 + 8 - 18
    -26 - 18
    -44
    like you see the math order is correct.
    the only error is the big empty space. maybe with time i can fix that and add parentheses working.
    but, i'm sorry, let me ask: what is the big difference between my code and Tokers?
    to be honest i did an array of a string, i think.... i think... the tokers start with these method too

  2. #17
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: can i convert a string into a math expression?

    Doesn't work with

    -1 + -2 * -3

    The first issue is here

    Code:
    if ((chr[0] == '-' && strMathExpression[i - 1] == '-'))
    When i is 0, i - 1 is a very large positive number (4294967295) as the type of i is unsigned. So the element access of strMathExpression is out of valid range.

    You are attempting to calculate from an infix expression by repeatedly iterating the expression looking for firstly * or /, evaluating this calculation, erasing these from the expression and then iterating again. Your vecOperator is a vector of elements (if the parse code was correct - see exprToTokens() in post #14) which mirrors the infix expression (although easier later if this was a vector of tokens - a token is really just a type and its value although other info such as precedence etc can also be stored). Whilst then attempting to evaluate these infix tokens by repeated iteration to find the highest precedence operator available (left to right associative) and token removal is one way, this will become very, very difficult to do once brackets are introduced. Also what about right to left associative operators such as ^ (power). I wouldn't like to try! The 'tried and tested' way to evaluate a tokenised infix expression is to first convert the tokens into a post-fix expression (commonly either by 'shunting-yard' (as in post #14) or by Recursive Descent Parser). This post-fix expression has all brackets removed and leaves the expression ready for evaluation from left to right - which is then quite straight forward.
    Last edited by 2kaud; April 6th, 2018 at 11:38 AM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  3. #18
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: can i convert a string into a math expression?

    Based upon your method, consider

    Code:
    #include <vector>
    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <cctype>
    using namespace std;
    
    void toExpr(string expr)
    {
    	const string opers = "*/+-";
    	const auto isnum = [](char ch) {return isdigit(ch) || (ch == '.'); };
    
    	vector<string> tokens;
    	bool gotoper = true;
    
    	expr.erase(remove_if(expr.begin(), expr.end(), [](char ch){return isspace(ch);}), expr.end());
    
    	for (const auto *p = expr.c_str(); *p;)
    		if (gotoper && ((isnum(*p) || (((*p == '-') || (*p == '+')) && isnum(*(p + 1)))))) {
    			const char* const b = ((*p == '-') || (*p == '+')) ? p++ : p;
    
    			for (; isnum(*p); ++p);
    			gotoper = false;
    			const auto s = string(b, p);
    
    			if (count(s.begin(), s.end(), '.') < 2)
    				tokens.push_back(s);
    			else {
    				cout << "Invalid number\n";
    				return;
    			}
    		} else
    			if (!gotoper) {
    				gotoper = true;
    				if (opers.find(*p) != string::npos)
    					tokens.push_back(string(1, *p++));
    				else {
    					cout << "Invalid operator\n";
    					return;
    				}
    			} else {
    				cout << "Invalid expression\n";
    				return;
    			}
    
    	if (gotoper) {
    		cout << "Missing final number\n";
    		return;
    	}
    
    	while (tokens.size() > 1) {
    		auto op = find_if(tokens.begin(), tokens.end(), [](const string& st){return st == "*" || st == "/";});
    
    		if (op == tokens.end())
    			op = tokens.begin() + 1;
    
    		const double op1 = stod(*(op - 1));
    		const double op2 = stod(*(op + 1));
    		double res = 0.0;
    
    		switch ((*op)[0]) {
    			case '*':
    				res = op1 * op2;
    				break;
    
    			case '/':
    				res = op1 / op2;
    				break;
    
    			case '+':
    				res = op1 + op2;
    				break;
    
    			case '-':
    				res = op1 - op2;
    				break;
    
    			default:
    				cout << "Fatal error\n";
    				return;
    		}
    
    		*(op - 1) = to_string(res);
    		tokens.erase(op, op + 2);
    	}
    
    	cout << stod(tokens.front()) << endl;
    }
    
    int main()
    {
    	cout << "Enter expression :";
    	string expr;
    
    	getline(std::cin, expr);
    
    	toExpr(expr);
    }
    For an example use

    Code:
    Enter expression :-1+-2*-3
    5
    
    Enter expression :1+2*3+4
    11
    
    Enter expression :2*3+3*4
    18
    
    Enter expression :2*3+3*4+4*5
    38
    Last edited by 2kaud; April 7th, 2018 at 06:03 AM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  4. #19
    Join Date
    Apr 2009
    Posts
    1,355

    Re: can i convert a string into a math expression?

    1st i'm sorry again... i was without network.. maybe now was fixed with long time
    "Doesn't work with

    -1 + -2 * -3"
    thank you so much... you have right.i didn't code for that. thank you so much.
    thank you so much for all.
    i will mark these thread Resolved. but 1st i will ask you a favor: like you have seen, i never used\learned Tokens.... can you give me a link for i start understand it and use it?

  5. #20
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: can i convert a string into a math expression?

    Complier and operating system design were the areas I majored in for my university degree many years ago. Back then, I learnt it all from lectures, books and experience writing programs! For the ideas behind parsing, have at look at https://en.wikipedia.org/wiki/Parsin...ession_grammar. Also try an internet search for 'parse an expression'. This will give loads of links. Don't just rely on provided code being always correct however!
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  6. #21
    Join Date
    Apr 2009
    Posts
    1,355

    Re: can i convert a string into a math expression?

    thank you so much.
    i can even translate it to Portuguese(my language).
    thank you so much for all

  7. #22
    Join Date
    Jun 2022
    Posts
    1

    Re: can i convert a string into a math expression?

    Thanks for post!

Page 2 of 2 FirstFirst 12

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured