C ++中用于数学表达式的正则表达式

时间:2016-01-19 22:02:14

标签: c++ regex

我有这个麻烦:我必须验证许多数学表达式的正确性,特别是检查连续的运算符+ - * /。 例如:

6+(69-9)+3

没问题

6++8-(52--*3)

没有。 我没有使用库<regex>,因为它只与C ++ 11兼容。 有没有其他方法可以解决这个问题?感谢。

5 个答案:

答案 0 :(得分:4)

您可以遍历表达式中的每个char

如果您遇到+,可以检查是否有其他+/* ...

此外,您可以将操作符组合在一起以防止代码重复。

int i = 0
while(!EOF) {
    switch(expression[i]) {
         case '+':
         case '*': //Do your syntax checks here
    }
    i++;
}

答案 1 :(得分:4)

嗯,一般情况下,你无法用正则表达式来解决这个问题。 Arithmethic表达式“语言”不能用常规语法描述。这是无上下文的语法。因此,如果你想要的是检查任意数学表达式的正确性,那么你将不得不编写一个解析器。

但是,如果你只需要确保你的字符串没有连续的+ - * /运算符,那么正则表达式就足够了。你可以写这样的东西[-+*/]{2,}。它会将子串与来自+-*/ set的2个或更多个连续符号匹配。

或类似([-+*/]\s*){2,}的内容,如果您还想处理5+ - * 123

等空格的情况

答案 2 :(得分:3)

好吧,如果可能的话,你必须定义一些规则。用Regex完全解析mathamatical语言是不可能的,但考虑到一些宽容,它可能有效。

问题在于,我们编写数学的方式通常可以解释为错误,但事实并非如此。例如:

 5--3 can be 5-(-3)

所以在这种情况下,你有两个选择:

  • 确保输入的括号足够好,没有两个操作符符合
  • 如果您发现--之类的内容,请将其视为特殊情况并进一步调查

如果公式实际上对您有利(具有明确定义的括号),那么您可以检查重复。例如:

--
+-
+*
-+

如果你有一个匹配,这意味着你的格式很差,你可以把它扔掉(或者你想做什么)。

您可以使用以下正则表达式检查此内容。您可以向[..] [..]添加更多约束。我在这里为您提供基础知识:

[+\-\*\\/][+\-\*\\/]

适用于以下示例(及更多):

6++8-(52--*3)
6+\8-(52--*3)
6+/8-(52--*3)

另一种可能更好的方法就是编写一个解析器。它将逐步处理方程式以检查其有效性。如果编写得好,解析器将100%准确。正则表达式方法会让您受到很多限制。

答案 3 :(得分:3)

除了检查括号是否平衡之外,您可以使用正则表达式来验证数学表达式的所有内容。也就是说,正则表达式只会确保打开和关闭的括号出现在它们应该出现的表达式的点上,而不是它们与其他括号的正确关系。

因此,您可以检查表达式是否与正则表达式匹配,以及括号是否平衡。如果只有一种括号,检查平衡括号非常简单:

bool check_balanced(const char* expr, char open, char close) {
  int parens = 0;
  for (const char* p = expr; *p; ++p) {
    if (*p == open) ++parens;
    else if (*p == close && parens-- == 0) return false;
  }
  return parens == 0;
}

要获得正则表达式,请注意,没有函数调用的数学表达式可以概括为:

BEFORE* VALUE AFTER* (BETWEEN BEFORE* VALUE AFTER*)*

其中:

  • BEFORE是子正则表达式,它匹配一个左括号或前缀一元运算符(如果你有前缀一元运算符;问题不明确)。

  • AFTER是一个子正则表达式,它匹配一个右括号,或者如果你有它们,则匹配一个后缀一元运算符。

  • BETWEEN是一个匹配二元运算符的子正则表达式。

  • VALUE是一个匹配值的子正则表达式。

例如,对于整数的普通四运算符算术,你可以:

  • BEFORE[-+(]

  • AFTER[)]

  • BETWEEN[-+*/]

  • VALUE:[[:digit:]] +

并将所有这些放在一起你最终可能会使用正则表达式:

^[-+(]*[[:digit:]]+[)]*([-+*/][-+(]*[[:digit:]]+[)]*)*$

如果你有一个Posix C库,你将拥有<regex.h>标题,它会为你提供regcomp and regexec。在Posix标准的引用页面底部有示例代码,所以我不打算在这里重复它。确保在REG_EXTENDED的最后一个参数中提供regcomp; REG_EXTENDED|REG_NOSUB,如示例代码中所示,可能更好,因为您不需要捕获而不需要捕获它们会加快速度。

答案 4 :(得分:2)

使用正则表达式没有真正的方法可以做到这一点,因为数学表达式本身并不常规。哎呀,even balancing parens isn't regular。通常,这将通过解析器完成。

编写递归下降解析器(IMO是最基本的解析器)的基本方法是:

  1. 为数学表达式编写语法。 (这些可在网上找到)
  2. 将输入标记为lexemes。 (这个 通常使用正则表达式完成。)
  3. 根据您看到的下一个词汇匹配表达式。
  4. 根据您的语法递归
  5. 快速Google搜索可以提供许多用C ++编写的递归下降解析器示例。