CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com

# Thread: [RESOLVED] can i convert a string into a math expression?

1. Senior Member
Join Date
Apr 2009
Posts
1,333

## 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=')',
Minus='-',
Multiplication ='*',
Space=' ',
Division ='/'
};

static bool IsMathOperator(char enMath)
{
switch(enMath)
{
case ParenthesesOpen:
case ParenthesesClose:
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. ## 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.

3. ## Re: can i convert a string into a math expression?

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.

4. Senior Member
Join Date
Apr 2009
Posts
1,333

## 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. ## 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!

6. Senior Member
Join Date
Apr 2009
Posts
1,333

## 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. Junior Member
Join Date
Jun 2022
Posts
1

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

Thanks for post!

#### Posting Permissions

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