It is my second attempt to make a math expression evaluator.
To evaluate an expression, I created a class that works like this:
-it removes all the blank spaces
-if brackets are present, it processes them by creating another evaluator with the expression inside those brackets
-it gets all the numbers and does first all the exponentiations, then the multiplications/divisions and finally sums all the numbers
For example, let's say I have the expression $$3*(3+4)^2+3*(5+6)$$
-replaces (3+4) and (5+6) with 7 and 11 $$3*7^2+3*11$$
-does 7^2 $$3*49+3*11$$
-does the multiplications $$147+33$$
-sums all the numbers $$180$$
If you know if there's something wrong or to optimize I'd really appreciate it
MathSolver.h
#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <map>
#include <functional>
void changeCharacters(std::string chars, std::string toChange, std::string &str)
{
int i = -1;
std::for_each(str.begin(), str.end(), [chars, toChange, &i, &str](char c)
{
i++;
for (auto &j : chars)
{
if (c == j)
{
str.erase(str.begin() + i);
str.insert(i, toChange);
break;
}
}
});
}
class MathSolver
{
private:
std::string exp;
std::vector<double> nums;
double result;
std::function<bool(char)> isPlusMinus = [](char c) {return c == '+' || c == '-'; };
std::function<bool(char)> isMultDiv = [](char c) {return c == '*' || c == '/'; };
public:
MathSolver(std::string exp)
{
exp.erase(std::remove(exp.begin(), exp.end(), ' '), exp.end());
if (exp.find_first_of("+-") != 0)
exp.insert(0, "+");
for (int i = 0; i < exp.length(); i++)
{
if (isPlusMinus(exp[i]))
exp.insert(i + 1, "1*");
}
changeCharacters("[{", "(", exp);
changeCharacters("]}", ")", exp);
changeCharacters(":", "/", exp);
this->exp = exp;
this->processBrackets();
this->parse();
}
void countBracks(std::vector< std::pair<int, int>> &bracks)
{
int parOC = 0;
for (int i = 0; i < exp.length(); i++)
{
if (exp[i] == '(')
{
if (parOC == 0)
bracks.push_back(std::make_pair(i, 0));
parOC++;
}
else if (exp[i] == ')')
{
parOC--;
if (parOC == 0)
bracks[bracks.size() - 1].second = i;
}
}
}
void processBrackets()
{
std::vector< std::pair<int, int>> bracks;
countBracks(bracks);
int count = bracks.size();
for (int i = 0; i < count; i++)
{
std::pair<int, int> j = bracks[0];
MathSolver solve(exp.substr(j.first + 1, j.second - 1 - j.first));
double res = solve.getResult();
std::stringstream ss;
ss << res;
exp.erase(exp.begin() + j.first, exp.begin() + j.second + 1);
exp.insert(j.first, ss.str());
bracks.clear();
countBracks(bracks);
}
}
void parse()
{
std::function<void(double&, std::istringstream&)> searchPow = [](double &num, std::istringstream &iss)
{
if (iss.peek() == '^')
{
char tmp2;
double tmp3;
iss >> tmp2 >> tmp3;
num = pow(num, tmp3);
}
};
double num;
char tmp;
std::istringstream iss(exp);
while ((int)iss.tellg() != EOF)
{
if (isPlusMinus(iss.peek()) && isdigit(exp[(int)iss.tellg() + 1]))
{
iss >> num;
searchPow(num, iss);
nums.push_back(num);
}
else if (isMultDiv(iss.peek()) && (isdigit(exp[(int)iss.tellg() + 1]) || isdigit(exp[(int)iss.tellg() + 2])))
{
iss >> tmp >> num;
searchPow(num, iss);
nums.push_back(num);
if (tmp == '/')
nums[nums.size() - 1] = 1 / nums[nums.size() - 1];
nums[nums.size() - 1] *= nums[nums.size() - 2];
nums[nums.size() - 2] = 0;
}
}
nums.erase(remove(nums.begin(), nums.end(), 0), nums.end());
for (auto i : nums)
result += i;
}
double getResult()
{
return result;
}
};