将包含数学的字符串转换为整数的递归函数
Posted
技术标签:
【中文标题】将包含数学的字符串转换为整数的递归函数【英文标题】:Recursive function to convert a string containing math to integer 【发布时间】:2020-03-28 23:24:08 【问题描述】:如果我有一个字符串 4+6*7/2
我想要一个计算值的函数,在本例中为 25。
为此,我编写了一个递归函数,逐个字符地分析字符串。
基本算法是这样的(或者应该是这样的):
如果我们现在分析的字符是普通密码并且我们没有遇到运算符(+、-、*、/),但我们将它存储在一个名为first_nr
的字符串中,最终将成为左侧的数字运营商。我们会这样做,直到遇到操作员。如果我们遇到一个运算符,我们会存储它是哪个运算符,以便我们知道以后要做什么。因为我们遇到了一个运算符,所以我们现在必须将以下数字添加到另一个名为second_nr
的字符串中,该字符串最终将成为运算符右侧的数字。 [我已经实现到这里] 当然我们还需要考虑计算的顺序,所以我会先忽略所有的加号和分钟,直到分析完所有的时间和除法。
这样,如果我有例如以下操作字符串:
123+789+4
。我的函数首先将123
放入first_nr
,然后查看运算符并将+
存储在operator
中。因为operator != NULL
现在它添加了以下数字,即789
到second_str
。结合这三个参数,我们可以形成first_nr + operator + second_str
,在这种情况下为123+789
。我的程序需要在遇到下一个运算符之前执行它,因此在这种情况下它将形成 912+4
并重复递归。
我努力了,但还是有很多漏洞。现在,如果我能让字符串 12+5
运行,我会很高兴。所以忽略除加号之外的所有运算符,忽略计算顺序(第一次和除法,然后是加号和最小值),并忽略一个字符串中的多个运算符。
如果我可以让最基本的字符串运行,我会改进我的算法以处理更复杂的字符串。
我的努力:
#include <iostream>
#include <string>
#include <algorithm>
//Enumeration of all the possible
//math operators
enum Operator
PLUS,
MIN,
TIMES,
DIVIDE,
UNDEFINED
;
/************************IGNORE********************/
Operator charToOperator(char c)
switch(c)
case '+':
return Operator::PLUS;
break;
case '-':
return Operator::MIN;
break;
case '*':
return Operator::TIMES;
break;
case '/':
return Operator::DIVIDE;
break;
default:
return Operator::UNDEFINED;
break;
/***************************************************/
/*
* Recursive function performing all the calculations from an action string.
* For example, if the string actions has value "5+7" in the first recursive run
* result should contain 12 after the last recursion.
*
* :param result: Double containing the calculated result after the last recursion
* :param actions: Action string (what you type in your calculator; e.g: 5+5). We analyze the first character of this string each time and add it to first_nr, second_nr, or make it the operator. First character gets deleted after each recursion
* :param first_nr: Empty at first recursion, number of left side of the operator. So in 55+77 this paramater will be "55". Gets resetted at the next operator
* :param second_nr: Idem as first_nr but for the right side of the operator.
* :param oper: Operation to calculate the first_nr and second_nr
*/
int calculate(double& result, std::string& actions, std::string& first_nr, std::string& second_nr, Operator& oper)
//Base-condition:
//If action string is empty return
if (actions == "")
return result;
//Get first character from action string
char c = actions[0];
//If first character is an operator
char operatorInChar[] = '+', '-', '*', '/';
if (std::find(std::begin(operatorInChar), std::end(operatorInChar), c) != std::end(operatorInChar))
//If operator is not yet set in a previous recursion
if (oper == NULL || oper == Operator::UNDEFINED)
oper = charToOperator(c);
//If second_nr is not empty, we need to calculate the two numbers together
if (second_nr != "")
//Update result
result = std::stod(first_nr) + std::stod(second_nr); //For now we only implement plus
//Calculation is done, so reset first_nr, second_nr and operator
//for the next 'first_nr [operator] second_nr' block in the action string
first_nr = "";
second_nr = "";
oper = Operator::UNDEFINED;
else
//If the character is not a operator but a number we append it to the correct nr
//we add to first_nr if the operator is not yet set, if we already encountered an operator
//we add to second_nr.
//e.g: actions = "123+789"
if (oper == NULL || oper == Operator::UNDEFINED)
first_nr += c;
else
second_nr += c;
//Remove first character from action string because it's analysed in this recursion
actions = actions.erase(0, 1);
//Make recursive call
return calculate(result, actions, first_nr, second_nr, oper);
int main()
//String we want to calculate
std::string str = "5+7";
std::string str_copy_for_output = str;
//Variables
double result = 0;
std::string first_nr = "";
std::string second_nr = "";
Operator oper = Operator::UNDEFINED;
//Call function
int calculation = calculate(result, str, first_nr, second_nr, oper);
//Output
std::cout << str_copy_for_output << " = " << calculation << std::endl;
return 0;
问题是result
始终为 0。任何帮助将不胜感激!
【问题讨论】:
actions = actions.erase(0, actions.size());
这会清除整个字符串,不是吗?
@O'Niel 你能解释一下这个表达式 4+6*7/2 是如何给出 23 的吗?
您可能还想研究递归下降解析器。
@VladfromMoscow 25。大声笑对不起。对我来说是深夜。
@user3365922 是的,在我的代码中对其进行了编辑。但同样的问题仍然存在。
【参考方案1】:
单步执行程序(使用调试器,printf
s 到处都是,或者至少在精神上)。几个有趣的点,按顺序排列:
-
oper 是 UNDEFINED(它不能是 NULL,因为它不是指针;编译器会警告你),first_nr 是“”,second_nr 是“”,actions 是“5+7”。
first_nr += c;
被执行。
oper 是 UNDEFINED,first_nr 是“5”,second_nr 是“”,action 是“+7”。
oper = charToOperator(c);
被执行。
oper 是 PLUS,first_nr 是“5”,second_nr 是“”,action 是“7”。
哎呀! “+”不再在actions
中,所以actions[0]
将永远不会在operatorInChar
中找到,并且该分支将不再执行。您可能需要在字符串末尾额外执行它。
【讨论】:
是的,我已经做过并且已经尝试过了。我知道如何调试,因此我发现我的算法有问题。我正在寻求有关如何修复我的算法的小而明确的建议。您能否详细说明一下“您可能需要在字符串末尾额外执行它”? @O'Niel 当您的算法到达actions == ""
的位置时,它需要处理排队的数据,即nr_first
、operator
和nr_second
(如果存在,如在您的例如),读取除第一个运算符之外的任何运算符后的操作方式相同。
我将代码放在第 77 行的 if (second_nr != "")
到第 54 行的 if (action == "")
中。得到了这个错误:terminating with uncaught exception of type std::invalid_argument: stod: no conversion
调试你的程序。去做吧。逐步检查值。请注意,NULL 在许多系统上是文字 0(包括您的系统,否则您的程序将无法编译),Operator::PLUS
也等于 0(作为第一个枚举器),因此等于 NULL。这绝对不是你想要的。考虑使用enum class
来防止此类错误。
问题确实在于将枚举与 NULL 进行比较。现在它适用于5+7
。回答采纳!谢谢!以上是关于将包含数学的字符串转换为整数的递归函数的主要内容,如果未能解决你的问题,请参考以下文章
用递归法将一个整数n转换成字符串,例如输入483,应输出字符串“483”。N的位数不确定,可以是任