您实际上并没有尝试将字符串拆分为数组。数组不会给你带来任何东西。你想要一个表达式树。或者至少是动态评估的递归下降解析。这会更容易,但效率较低。
在 StackOverflow 上一定有很多关于递归下降表达式解析器的问题/答案。使用搜索框获取想法。
演示
为了完全矫枉过正,这里有一个带有动态(单字母)变量和一些测试用例的公式评估函数示例。
它使用 C++14 和 Boost Spirit X3。这里的“递归下降”解析器是从PEG rules 生成的,而不是手写的。
Live On Coliru
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <map>
using VarMap = std::map<char, double>;
namespace formula {
namespace detail {
using namespace boost::spirit::x3;
#define BIN(f) ([](auto &ctx) { _val(ctx) = f(_val(ctx), _attr(ctx)); })
#define BINOP(op) BIN(([](auto a, auto b) { return a op b; }))
#define IDENT ([](auto &ctx) { _val(ctx) = _attr(ctx); })
static VarMap var_map;
auto lookup = [](auto& ctx) { _val(ctx) = var_map.at(_attr(ctx)); };
rule<struct f_, double> factor {"factor"};
rule<struct t_, double> term {"term"};
rule<struct x_, double> expo {"expo"};
auto var = rule<struct _v, double> {"var"}
= alpha [lookup];
auto literal = !lit('-') >> double_;
auto simple = rule<struct _l, double> {"simple"}
= ('(' >> term >> ')') | var | literal;
auto expo_def
= simple [IDENT] >> *('^' >> expo)[BIN(pow)];
auto factor_def = expo [IDENT] >> *(
'*' >> factor [BINOP(*)]
| '/' >> factor [BINOP(/)]
| factor [BINOP(*)]
);
auto term_def = factor [IDENT] >> *(
'+' >> term [BINOP(+)]
| '-' >> term [BINOP(-)]
);
BOOST_SPIRIT_DEFINE(expo, factor, term)
auto expr = skip(space) [eps > term > eoi];
}
struct evaluation_error : std::runtime_error {
evaluation_error(std::string const& msg) : std::runtime_error(msg) {}
};
double eval(std::string const& formula, VarMap vars) {
using namespace std::string_literals;
detail::var_map = vars;
double value;
try {
bool ok = parse(begin(formula), end(formula), detail::expr, value);
assert(ok);
return value;
} catch(boost::spirit::x3::expectation_failure<std::string::const_iterator> const& e) {
throw evaluation_error("syntax: expect " + e.which() + " at '" + std::string(e.where(), formula.end()) + "'");
} catch(std::out_of_range const& e) {
throw evaluation_error("variable undefined");
} catch(std::exception const& e) {
throw evaluation_error("eval: "s + e.what());
}
}
}
int main() {
for (auto formula : { "", "0", "2", "x", "2x",
"x^2",
"2x^2",
"2x^2-1x",
"2x^2-sin x",
"x^(1/2)",
"(x^(1/2))^2",
})
try {
std::cout << "Function f(x) -> " << formula << "\n";
for (double x = 0; x < 10; x += 1)
std::cout << " - f(" << x << ") -> " << formula::eval(formula, {{'x', x}}) << "\n";
} catch(formula::evaluation_error const& e) {
std::cout << "Oops: " << e.what() << "\n";
}
}
打印
Function f(x) ->
- f(0) -> Oops: syntax: expect term at ''
Function f(x) -> 0
- f(0) -> 0
- f(1) -> 0
- f(2) -> 0
- f(3) -> 0
- f(4) -> 0
- f(5) -> 0
- f(6) -> 0
- f(7) -> 0
- f(8) -> 0
- f(9) -> 0
Function f(x) -> 2
- f(0) -> 2
- f(1) -> 2
- f(2) -> 2
- f(3) -> 2
- f(4) -> 2
- f(5) -> 2
- f(6) -> 2
- f(7) -> 2
- f(8) -> 2
- f(9) -> 2
Function f(x) -> x
- f(0) -> 0
- f(1) -> 1
- f(2) -> 2
- f(3) -> 3
- f(4) -> 4
- f(5) -> 5
- f(6) -> 6
- f(7) -> 7
- f(8) -> 8
- f(9) -> 9
Function f(x) -> 2x
- f(0) -> 0
- f(1) -> 2
- f(2) -> 4
- f(3) -> 6
- f(4) -> 8
- f(5) -> 10
- f(6) -> 12
- f(7) -> 14
- f(8) -> 16
- f(9) -> 18
Function f(x) -> x^2
- f(0) -> 0
- f(1) -> 1
- f(2) -> 4
- f(3) -> 9
- f(4) -> 16
- f(5) -> 25
- f(6) -> 36
- f(7) -> 49
- f(8) -> 64
- f(9) -> 81
Function f(x) -> 2x^2
- f(0) -> 0
- f(1) -> 2
- f(2) -> 8
- f(3) -> 18
- f(4) -> 32
- f(5) -> 50
- f(6) -> 72
- f(7) -> 98
- f(8) -> 128
- f(9) -> 162
Function f(x) -> 2x^2-1x
- f(0) -> 0
- f(1) -> 1
- f(2) -> 6
- f(3) -> 15
- f(4) -> 28
- f(5) -> 45
- f(6) -> 66
- f(7) -> 91
- f(8) -> 120
- f(9) -> 153
Function f(x) -> 2x^2-sin x
- f(0) -> Oops: variable undefined
Function f(x) -> x^(1/2)
- f(0) -> 0
- f(1) -> 1
- f(2) -> 1.41421
- f(3) -> 1.73205
- f(4) -> 2
- f(5) -> 2.23607
- f(6) -> 2.44949
- f(7) -> 2.64575
- f(8) -> 2.82843
- f(9) -> 3
Function f(x) -> (x^(1/2))^2
- f(0) -> 0
- f(1) -> 1
- f(2) -> 2
- f(3) -> 3
- f(4) -> 4
- f(5) -> 5
- f(6) -> 6
- f(7) -> 7
- f(8) -> 8
- f(9) -> 9