This is a follow-up question for Advanced String Calculator in C++. Considering the suggestions mentioned in MrBean Bremen's answer, I am trying to update the implementation as below.
The experimental implementation
StringCalculatorclassclass StringCalculator { public: StringCalculator(const std::string& input) { input_string = input; } long double get_result() { if(result == std::nullopt) { auto input_without_space = remove_spaces(input_string); auto braces_levels = get_braces_levels(input_without_space); auto braces_level_max = *max_element(braces_levels.begin(), braces_levels.end()); while(braces_level_max > 0) { std::size_t inner_braces_start = 0; std::size_t inner_braces_end = 0; if(braces_levels[0] == braces_level_max) { inner_braces_start = 0; } for(std::size_t index = 1; index < braces_levels.size(); ++index) { if( braces_levels[index - 1] == braces_level_max - 1 && braces_levels[index] == braces_level_max) { inner_braces_start = index; break; } } for(std::size_t index = inner_braces_start; index < braces_levels.size(); ++index) { if(braces_levels[index] == braces_level_max) { inner_braces_end = index; } else { break; } } if(input_without_space.substr(inner_braces_start + 1, inner_braces_end - inner_braces_start - 1) == "") { throw std::runtime_error("Empty content in braces"); } StringCalculatorHelper sch(input_without_space.substr(inner_braces_start + 1, inner_braces_end - inner_braces_start - 1)); input_without_space.replace( inner_braces_start, inner_braces_end - inner_braces_start + 1, std::format("{:.20f}", sch.get_result())); braces_levels = get_braces_levels(input_without_space); braces_level_max = *max_element(braces_levels.begin(), braces_levels.end()); } StringCalculatorHelper sch(input_without_space); result = sch.get_result(); } return result.value(); } private: std::optional<double> result; std::string input_string; constexpr std::vector<int> get_braces_levels(std::string_view input) { std::vector<int> braces_levels; int braces_level = 0; for(std::size_t index = 0; index < input.size(); ++index) { if(input[index] == '(') { braces_level = braces_level + 1; } braces_levels.emplace_back(braces_level); if(input[index] == ')') { braces_level = braces_level - 1; } } if(braces_level!=0) { throw std::runtime_error("Braces unbalanced"); } return braces_levels; } // copy from https://stackoverflow.com/a/83481/6667035 std::string remove_spaces(std::string str) { std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' '); str.erase(end_pos, str.end()); return str; } };StringCalculatorHelperclassclass StringCalculatorHelper { public: StringCalculatorHelper(const std::string& input) { input_string = input; } long double get_result() { if(result == std::nullopt) { numbers.clear(); operators.clear(); // remove spaces auto input_without_space = remove_spaces(input_string); parse(input_without_space); while(operators.size() > 0) { perform_computing(); } result = numbers[0]; } return result.value(); } private: std::optional<double> result; std::string input_string; std::vector<long double> numbers; // define operators as enums enum class Operator { add, subtract, multiply, divide, pow, abs, sqrt, log, sin, cos, tan, cot, sec, csc, sinh, cosh, tanh, asin, acos, atan }; std::vector<Operator> operators; // define basic operator strings with corresponding enums constexpr static std::pair<std::string, Operator> basic_op_names[] = { {"+", Operator::add }, {"-", Operator::subtract }, {"*", Operator::multiply }, {"/", Operator::divide }, {"^", Operator::pow }, }; // define advanced operator strings with corresponding enums constexpr static std::pair<std::string, Operator> advanced_op_names[] = { {"asin", Operator::asin }, {"acos", Operator::acos }, {"atan", Operator::atan }, {"sinh", Operator::sinh }, {"cosh", Operator::cosh }, {"tanh", Operator::tanh }, {"abs", Operator::abs }, {"sqrt", Operator::sqrt }, {"log", Operator::log }, {"sin", Operator::sin }, {"cos", Operator::cos }, {"tan", Operator::tan }, {"cot", Operator::cot }, {"sec", Operator::sec }, {"csc", Operator::csc }, }; constexpr void print_operator(Operator op) { switch (op) { case Operator::sqrt: std::cout << "Operator::sqrt"; break; case Operator::abs: std::cout << "Operator::abs"; break; case Operator::log: std::cout << "Operator::log"; break; case Operator::sin: std::cout << "Operator::sin"; break; case Operator::cos: std::cout << "Operator::cos"; break; case Operator::tan: std::cout << "Operator::tan"; break; case Operator::cot: std::cout << "Operator::cot"; break; case Operator::sec: std::cout << "Operator::sec"; break; case Operator::csc: std::cout << "Operator::csc"; break; case Operator::sinh: std::cout << "Operator::sinh"; break; case Operator::cosh: std::cout << "Operator::cosh"; break; case Operator::tanh: std::cout << "Operator::tanh"; break; case Operator::asin: std::cout << "Operator::asin"; break; case Operator::acos: std::cout << "Operator::acos"; break; case Operator::atan: std::cout << "Operator::atan"; break; case Operator::add: std::cout << "Operator::add"; break; case Operator::subtract: std::cout << "Operator::subtract"; break; case Operator::multiply: std::cout << "Operator::multiply"; break; case Operator::divide: std::cout << "Operator::divide"; break; case Operator::pow: std::cout << "Operator::pow"; break; } } constexpr void parse(std::string_view input_string) { std::string single_number = ""; for(std::size_t index = 0; index < input_string.size(); ++index) { for (const auto& op : advanced_op_names) { if(input_string.substr(index, op.first.size()) == op.first) { operators.emplace_back(op.second); index += op.first.size(); if(single_number == "") { single_number = "0"; } numbers.emplace_back(std::stold(single_number)); single_number = ""; } } if(std::isdigit(input_string[index]) || input_string[index] == '.' || input_string[index] == ',') single_number = single_number + input_string[index]; for (const auto& op : basic_op_names) { if(input_string.substr(index, 1) == op.first) { operators.emplace_back(op.second); if(single_number == "") { single_number = "0"; } numbers.emplace_back(std::stold(single_number)); single_number = ""; } } } if(single_number == "") { single_number = "0"; } numbers.emplace_back(std::stold(single_number)); } constexpr void perform_computing() { // level 0 computation: 0- for(std::size_t index = 0; index < operators.size(); ++index) { if(operators[index] == Operator::subtract && numbers[index] == 0 && numbers[index + 1] != 0) { numbers[index] = -numbers[index + 1]; reduce_operators_and_numbers(index); return; } } // level 1 computation: advanced functions for(std::size_t index = 0; index < operators.size(); ++index) { bool operatorFound = true; switch (operators[index]) { case Operator::sqrt: numbers[index] = std::sqrt(numbers[index + 1]); break; case Operator::abs: numbers[index] = std::abs(numbers[index + 1]); break; case Operator::log: numbers[index] = std::log(numbers[index + 1]); break; case Operator::sin: numbers[index] = std::sin(numbers[index + 1]); break; case Operator::cos: numbers[index] = std::cos(numbers[index + 1]); break; case Operator::tan: numbers[index] = std::tan(numbers[index + 1]); break; case Operator::cot: numbers[index] = 1 / std::tan(numbers[index + 1]); break; case Operator::sec: numbers[index] = 1 / std::cos(numbers[index + 1]); break; case Operator::csc: numbers[index] = 1 / std::sin(numbers[index + 1]); break; case Operator::sinh: numbers[index] = std::sinh(numbers[index + 1]); break; case Operator::cosh: numbers[index] = std::cosh(numbers[index + 1]); break; case Operator::tanh: numbers[index] = std::tanh(numbers[index + 1]); break; case Operator::asin: numbers[index] = std::asin(numbers[index + 1]); break; case Operator::acos: numbers[index] = std::acos(numbers[index + 1]); break; case Operator::atan: numbers[index] = std::atan(numbers[index + 1]); break; default: operatorFound = false; break; } if (operatorFound) { reduce_operators_and_numbers(index); return; } } // level 2 computation: ^ (power) for(std::size_t rIndex = operators.size(); rIndex > 0; --rIndex) { std::size_t index = rIndex - 1; if(operators[index] == Operator::pow) { numbers[index] = std::pow(numbers[index], numbers[index + 1]); reduce_operators_and_numbers(index); return; } } // level 3 computation: * (multiplication) and / (division) for(std::size_t index = 0; index < operators.size(); ++index) { if(operators[index] == Operator::multiply) { numbers[index] = numbers[index] * numbers[index + 1]; reduce_operators_and_numbers(index); return; } if(operators[index] == Operator::divide) { numbers[index] = numbers[index] / numbers[index + 1]; reduce_operators_and_numbers(index); return; } } // level 4 computation: + (addition) and - (subtraction) for(std::size_t index = 0; index < operators.size(); ++index) { if(operators[index] == Operator::add) { numbers[index] = numbers[index] + numbers[index + 1]; reduce_operators_and_numbers(index); return; } if(operators[index] == Operator::subtract) { numbers[index] = numbers[index] - numbers[index + 1]; reduce_operators_and_numbers(index); return; } } } constexpr void reduce_operators_and_numbers(std::size_t index) { reduce_operators(index); reduce_numbers(index); } constexpr void reduce_operators(std::size_t index) { for(std::size_t index1 = index; index1 < operators.size() - 1; ++index1) { operators[index1] = operators[index1 + 1]; } operators.resize(operators.size() - 1); } constexpr void reduce_numbers(std::size_t index) { for(std::size_t index1 = index; index1 < numbers.size() - 2; ++index1) { numbers[index1 + 1] = numbers[index1 + 2]; } numbers.resize(numbers.size() - 1); } // copy from https://stackoverflow.com/a/83481/6667035 std::string remove_spaces(std::string str) { std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' '); str.erase(end_pos, str.end()); return str; } };
Full Testing Code
The full testing code:
// Advanced String Calculator with asin, acos, atan Functions in C++
#include <algorithm>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <concepts>
#include <execution>
#include <format>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <optional>
#include <queue>
#include <ranges>
#include <stack>
#include <string>
// From https://stackoverflow.com/a/37264642/6667035
#ifndef NDEBUG
# define M_Assert(Expr, Msg) \
M_Assert_Helper(#Expr, Expr, __FILE__, __LINE__, Msg)
#else
# define M_Assert(Expr, Msg) ;
#endif
void M_Assert_Helper(const char* expr_str, bool expr, const char* file, int line, std::string msg)
{
if (!expr)
{
std::cerr << "Assert failed:\t" << msg << "\n"
<< "Expected:\t" << expr_str << "\n"
<< "Source:\t\t" << file << ", line " << line << "\n";
abort();
}
}
struct recursive_print_fn
{
template<std::ranges::input_range T>
constexpr auto operator()(const T& input, const int level = 0) const
{
T output = input;
std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
std::ranges::transform(std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output),
[&](auto&& x)
{
std::cout << std::string(level, ' ') << x << std::endl;
return x;
}
);
return output;
}
template<std::ranges::input_range T>
requires (std::ranges::input_range<std::ranges::range_value_t<T>>)
constexpr auto operator()(const T& input, const int level = 0) const
{
T output = input;
std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
std::ranges::transform(std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output),
[&](auto&& element)
{
return operator()(element, level + 1);
}
);
return output;
}
};
inline constexpr recursive_print_fn recursive_print;
class StringCalculatorHelper
{
public:
StringCalculatorHelper(const std::string& input)
{
input_string = input;
}
long double get_result()
{
if(result == std::nullopt)
{
numbers.clear();
operators.clear();
// remove spaces
auto input_without_space = remove_spaces(input_string);
parse(input_without_space);
while(operators.size() > 0)
{
perform_computing();
}
result = numbers[0];
}
return result.value();
}
private:
std::optional<double> result;
std::string input_string;
std::vector<long double> numbers;
// define operators as enums
enum class Operator
{
add,
subtract,
multiply,
divide,
pow,
abs,
sqrt,
log,
sin,
cos,
tan,
cot,
sec,
csc,
sinh,
cosh,
tanh,
asin,
acos,
atan
};
std::vector<Operator> operators;
// define basic operator strings with corresponding enums
constexpr static std::pair<std::string, Operator> basic_op_names[] = {
{"+", Operator::add },
{"-", Operator::subtract },
{"*", Operator::multiply },
{"/", Operator::divide },
{"^", Operator::pow },
};
// define advanced operator strings with corresponding enums
constexpr static std::pair<std::string, Operator> advanced_op_names[] = {
{"asin", Operator::asin },
{"acos", Operator::acos },
{"atan", Operator::atan },
{"sinh", Operator::sinh },
{"cosh", Operator::cosh },
{"tanh", Operator::tanh },
{"abs", Operator::abs },
{"sqrt", Operator::sqrt },
{"log", Operator::log },
{"sin", Operator::sin },
{"cos", Operator::cos },
{"tan", Operator::tan },
{"cot", Operator::cot },
{"sec", Operator::sec },
{"csc", Operator::csc },
};
constexpr void print_operator(Operator op)
{
switch (op)
{
case Operator::sqrt:
std::cout << "Operator::sqrt";
break;
case Operator::abs:
std::cout << "Operator::abs";
break;
case Operator::log:
std::cout << "Operator::log";
break;
case Operator::sin:
std::cout << "Operator::sin";
break;
case Operator::cos:
std::cout << "Operator::cos";
break;
case Operator::tan:
std::cout << "Operator::tan";
break;
case Operator::cot:
std::cout << "Operator::cot";
break;
case Operator::sec:
std::cout << "Operator::sec";
break;
case Operator::csc:
std::cout << "Operator::csc";
break;
case Operator::sinh:
std::cout << "Operator::sinh";
break;
case Operator::cosh:
std::cout << "Operator::cosh";
break;
case Operator::tanh:
std::cout << "Operator::tanh";
break;
case Operator::asin:
std::cout << "Operator::asin";
break;
case Operator::acos:
std::cout << "Operator::acos";
break;
case Operator::atan:
std::cout << "Operator::atan";
break;
case Operator::add:
std::cout << "Operator::add";
break;
case Operator::subtract:
std::cout << "Operator::subtract";
break;
case Operator::multiply:
std::cout << "Operator::multiply";
break;
case Operator::divide:
std::cout << "Operator::divide";
break;
case Operator::pow:
std::cout << "Operator::pow";
break;
}
}
constexpr void parse(std::string_view input_string)
{
std::string single_number = "";
for(std::size_t index = 0; index < input_string.size(); ++index)
{
for (const auto& op : advanced_op_names)
{
if(input_string.substr(index, op.first.size()) == op.first)
{
operators.emplace_back(op.second);
index += op.first.size();
if(single_number == "")
{
single_number = "0";
}
numbers.emplace_back(std::stold(single_number));
single_number = "";
}
}
if(std::isdigit(input_string[index]) || input_string[index] == '.' || input_string[index] == ',')
single_number = single_number + input_string[index];
for (const auto& op : basic_op_names)
{
if(input_string.substr(index, 1) == op.first)
{
operators.emplace_back(op.second);
if(single_number == "")
{
single_number = "0";
}
numbers.emplace_back(std::stold(single_number));
single_number = "";
}
}
}
if(single_number == "")
{
single_number = "0";
}
numbers.emplace_back(std::stold(single_number));
}
constexpr void perform_computing()
{
// level 0 computation: 0-
for(std::size_t index = 0; index < operators.size(); ++index)
{
if(operators[index] == Operator::subtract && numbers[index] == 0 && numbers[index + 1] != 0)
{
numbers[index] = -numbers[index + 1];
reduce_operators_and_numbers(index);
return;
}
}
// level 1 computation: advanced functions
for(std::size_t index = 0; index < operators.size(); ++index)
{
bool operatorFound = true;
switch (operators[index])
{
case Operator::sqrt:
numbers[index] = std::sqrt(numbers[index + 1]);
break;
case Operator::abs:
numbers[index] = std::abs(numbers[index + 1]);
break;
case Operator::log:
numbers[index] = std::log(numbers[index + 1]);
break;
case Operator::sin:
numbers[index] = std::sin(numbers[index + 1]);
break;
case Operator::cos:
numbers[index] = std::cos(numbers[index + 1]);
break;
case Operator::tan:
numbers[index] = std::tan(numbers[index + 1]);
break;
case Operator::cot:
numbers[index] = 1 / std::tan(numbers[index + 1]);
break;
case Operator::sec:
numbers[index] = 1 / std::cos(numbers[index + 1]);
break;
case Operator::csc:
numbers[index] = 1 / std::sin(numbers[index + 1]);
break;
case Operator::sinh:
numbers[index] = std::sinh(numbers[index + 1]);
break;
case Operator::cosh:
numbers[index] = std::cosh(numbers[index + 1]);
break;
case Operator::tanh:
numbers[index] = std::tanh(numbers[index + 1]);
break;
case Operator::asin:
numbers[index] = std::asin(numbers[index + 1]);
break;
case Operator::acos:
numbers[index] = std::acos(numbers[index + 1]);
break;
case Operator::atan:
numbers[index] = std::atan(numbers[index + 1]);
break;
default:
operatorFound = false;
break;
}
if (operatorFound)
{
reduce_operators_and_numbers(index);
return;
}
}
// level 2 computation: ^ (power)
for(std::size_t rIndex = operators.size(); rIndex > 0; --rIndex)
{
std::size_t index = rIndex - 1;
if(operators[index] == Operator::pow)
{
numbers[index] = std::pow(numbers[index], numbers[index + 1]);
reduce_operators_and_numbers(index);
return;
}
}
// level 3 computation: * (multiplication) and / (division)
for(std::size_t index = 0; index < operators.size(); ++index)
{
if(operators[index] == Operator::multiply)
{
numbers[index] = numbers[index] * numbers[index + 1];
reduce_operators_and_numbers(index);
return;
}
if(operators[index] == Operator::divide)
{
numbers[index] = numbers[index] / numbers[index + 1];
reduce_operators_and_numbers(index);
return;
}
}
// level 4 computation: + (addition) and - (subtraction)
for(std::size_t index = 0; index < operators.size(); ++index)
{
if(operators[index] == Operator::add)
{
numbers[index] = numbers[index] + numbers[index + 1];
reduce_operators_and_numbers(index);
return;
}
if(operators[index] == Operator::subtract)
{
numbers[index] = numbers[index] - numbers[index + 1];
reduce_operators_and_numbers(index);
return;
}
}
}
constexpr void reduce_operators_and_numbers(std::size_t index)
{
reduce_operators(index);
reduce_numbers(index);
}
constexpr void reduce_operators(std::size_t index)
{
for(std::size_t index1 = index; index1 < operators.size() - 1; ++index1)
{
operators[index1] = operators[index1 + 1];
}
operators.resize(operators.size() - 1);
}
constexpr void reduce_numbers(std::size_t index)
{
for(std::size_t index1 = index; index1 < numbers.size() - 2; ++index1)
{
numbers[index1 + 1] = numbers[index1 + 2];
}
numbers.resize(numbers.size() - 1);
}
// copy from https://stackoverflow.com/a/83481/6667035
std::string remove_spaces(std::string str)
{
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());
return str;
}
};
class StringCalculator
{
public:
StringCalculator(const std::string& input)
{
input_string = input;
}
long double get_result()
{
if(result == std::nullopt)
{
auto input_without_space = remove_spaces(input_string);
auto braces_levels = get_braces_levels(input_without_space);
auto braces_level_max = *max_element(braces_levels.begin(), braces_levels.end());
while(braces_level_max > 0)
{
std::size_t inner_braces_start = 0;
std::size_t inner_braces_end = 0;
if(braces_levels[0] == braces_level_max)
{
inner_braces_start = 0;
}
for(std::size_t index = 1; index < braces_levels.size(); ++index)
{
if( braces_levels[index - 1] == braces_level_max - 1 &&
braces_levels[index] == braces_level_max)
{
inner_braces_start = index;
break;
}
}
for(std::size_t index = inner_braces_start; index < braces_levels.size(); ++index)
{
if(braces_levels[index] == braces_level_max)
{
inner_braces_end = index;
}
else
{
break;
}
}
if(input_without_space.substr(inner_braces_start + 1, inner_braces_end - inner_braces_start - 1) == "")
{
throw std::runtime_error("Empty content in braces");
}
StringCalculatorHelper sch(input_without_space.substr(inner_braces_start + 1, inner_braces_end - inner_braces_start - 1));
input_without_space.replace(
inner_braces_start,
inner_braces_end - inner_braces_start + 1,
std::format("{:.20f}", sch.get_result()));
braces_levels = get_braces_levels(input_without_space);
braces_level_max = *max_element(braces_levels.begin(), braces_levels.end());
}
StringCalculatorHelper sch(input_without_space);
result = sch.get_result();
}
return result.value();
}
private:
std::optional<double> result;
std::string input_string;
constexpr std::vector<int> get_braces_levels(std::string_view input)
{
std::vector<int> braces_levels;
int braces_level = 0;
for(std::size_t index = 0; index < input.size(); ++index)
{
if(input[index] == '(')
{
braces_level = braces_level + 1;
}
braces_levels.emplace_back(braces_level);
if(input[index] == ')')
{
braces_level = braces_level - 1;
}
}
if(braces_level!=0)
{
throw std::runtime_error("Braces unbalanced");
}
return braces_levels;
}
// copy from https://stackoverflow.com/a/83481/6667035
std::string remove_spaces(std::string str)
{
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());
return str;
}
};
// From: https://stackoverflow.com/a/37686/6667035
constexpr bool AreSame(double a, double b, int tolerance) {
return std::fabs(a - b) < tolerance * std::numeric_limits<double>::epsilon();
}
constexpr auto testExpression(std::string input_expression, long double expect_result, int tolerance)
{
StringCalculator sc1(input_expression);
M_Assert(
AreSame(sc1.get_result(), expect_result, tolerance),
input_expression + " test case failed");
}
int main()
{
auto start = std::chrono::system_clock::now();
testExpression("-12.3456 + 2 ^ 3 * 3.123", 12.6384, 1);
testExpression("-0.12345 * 3 - 5", -5.37035, 1);
testExpression("1024*2+2048*4", 10240, 1);
testExpression("10-2*3+2*2-7", 1, 1);
testExpression("1+(2+(3+4))+2+3", 15, 1);
testExpression("1+sin(1)", 1.841470984807897, 10);
testExpression("1+sin(2^2)", 0.243197504692072, 10);
testExpression("1+cos(2^(2+2))", 0.042340519676615, 10);
testExpression("1+tan((1+2)*3)", 0.547684340558190, 10);
testExpression("1+cot(tan((1+2)*3))", -1.057976196110096, 10);
testExpression("1+sec(cot(tan((1+2)*3)))", -1.136132630785074, 10);
testExpression("2+3*csc(-2)", -1.299250510883849, 10);
testExpression("2 * sqrt(3) + 1", 4.464101615137754, 10);
testExpression("2 * sqrt(abs(-3)) + 1", 4.464101615137754, 10);
testExpression("4^3^2", 262144, 10);
testExpression("log(4^3)", 4.158883083359671, 10);
testExpression("sinh(-1)", -1.175201193643801, 10);
testExpression("cosh(sinh(-1))", 1.773775678340353, 10);
testExpression("tanh(cosh(-1))", 0.912636575963212, 10);
testExpression("tanh(-1)", -0.761594155955765, 10);
testExpression("asin(sin(-10))", 0.575222039230620, 10);
testExpression("acos(cos(-1))", 1, 10);
testExpression("tan(atan(-1))", -1.000000000000000, 10);
testExpression("tan(atan(-1)^2)", 0.709164626405133, 10);
testExpression("asin(sin(-3)^2)", 0.019916173286866, 10);
testExpression("tanh(cosh(-1)+tanh(cosh(-2)))", 0.987686168952949, 10);
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
return 0;
}
The output of the test code above:
Computation finished at Mon May 13 15:47:44 2024
elapsed time: 0.00106393
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
What changes has been made in the code since last question?
I am trying to follow the suggestions mentioned in MrBean Bremen's answer to implement an advanced string calculator with more function support in this post.
Why a new review is being asked for?
Please review the implementation of
StringCalculatorandStringCalculatorHelperclass and its tests.