递归计算字符串中的表达式

时间:2018-12-15 12:13:08

标签: c++ string parsing recursion

让我们说我们想对字符串中的表达式求值。为了简单起见,在示例中用(###)表示的表达式。为了简单起见,我们仅在示例中计算主题标签。表达式可以嵌套。

#include <iostream>
#include <string>

std::string expression{ "(###(##)#(###)##)" };

int countHash(std::string::iterator stringIterator, std::string::iterator stringEnd)
{
    int result = 0;
    while (stringIterator != stringEnd)
    {
        if (*stringIterator == '#')
        {
            result += 1;
        }
        else if (*stringIterator == '(')
        {
            result += countHash(++stringIterator, stringEnd);
        }
        else if (*stringIterator == ')')
        {
            return result += countHash(++stringIterator, stringEnd);
        }
        ++stringIterator;
    }
    return result;
}

int main()
{
    std::cout << countHash(expression.begin(), expression.end()) << std::endl;
    return 0;
}

输出:51

扩展输出:11

所以我的问题是当我从递归调用中返回时,迭代器没有更新。它落后了。该处理多次遍历字符串的各个部分。我该如何处理?

我的主要目标是能够评估这样的表达式:

std::string expr = "(+1 (+22 3 25) 5 (+44 (*3 2)))";
EXPECT(106== evalExpression(expr.begin(), expr.end()));

谢谢。

编辑:

我根据评论中的建议更新了问题。

2 个答案:

答案 0 :(得分:0)

#include <string>
#include <iostream>

std::string expression{ "#####-###-##" };

int countHash(std::string::iterator & stringIterator, std::string::iterator stringEnd)
{
  int result = 0;
  while (stringIterator != stringEnd)
  {
    switch (*stringIterator++)
    {
    case '#':
      result += 1;
      break;
    case '-':
      result += countHash(stringIterator, stringEnd);
      break;
    default:
      // indicate error ?
      break;
    }
  }
  return result;
}

int main()
{
  std::string::iterator b = expression.begin();
  std::cout << countHash(b, expression.end()) << std::endl;
  return 0;
}

答案 1 :(得分:0)

好的,所以在我编辑原始问题时,这是一个解决方案:

#include <iostream>
#include <string>

std::string expression{ "(###((##)#)(#(#)#)#(#))" };

int countHash(std::string::iterator& stringIterator, std::string::iterator stringEnd)
{
    int result = 0;
    while (stringIterator != stringEnd)
    {
        if (*stringIterator == '#')
        {
            result += 1;
        }
        else if (*stringIterator == '(')
        {
            result += countHash(++stringIterator, stringEnd);
            continue;
        }
        else if (*stringIterator == ')')
        {
            ++stringIterator;
            return result;
        }
        ++stringIterator;
    }
    return result;
}

int countHash(std::string expression)
{
    auto it = expression.begin();
    return countHash(it, expression.end());
}

int main()
{
    std::cout << countHash(expression) << std::endl;
    return 0;
}

输出:11

所以重要的一点是,您需要通过引用传递字符串,以避免在从递归调用返回后多次处理字符串的相同段。

我还遇到的困难是您需要在continue循环中递归调用之后执行while。这是因为您不想在递归调用返回后递增stringIterator。 您也可以使用后增量运算符和switch-case来完成此操作,就像@bruno在他的回答中所做的那样。那是我的见识。如果您不仅要检查字符,switch-case是不可能的。您可以使用do-while循环,但我不喜欢这样。

更重要的是,在从)分支返回之前,您需要增加迭代器。这是因为这是表达式的结尾,如果是递归调用,则您要继续在调用者端使用该表达式。

另一个问题是,如果函数引用了迭代器,则无法传递expression.begin()

对于

std::string expr = "(+1 (+22 3 25) 5 (+44 (*3 2)))";

表达式我的解决方案可从https://github.com/bencemeszaroshu/expeval/blob/master/expeval/expeval.cpp获得。我现在不喜欢它,但是稍后我将尝试对其进行改进。 (很高兴听到建议。)但是它正在工作。感谢大家的帮助,我将@bruno回答标记为已接受,因为它对我的帮助最大。