正则表达式验证数学表达式

时间:2016-02-22 17:46:33

标签: java regex validation math expression

我试图确定给定的输入是否是有效的数学表达式。这是我提出的当前代码,但如果Input是单个整数(例如100,200,5,7),它只会返回true。

Pattern pattern = Pattern.compile("-?\\w+|[-+*%/()]");
Matcher match = pattern.matcher(Input);

if(pattern.matcher(Input).matches())
{
    System.out.print("True");
}
else
    System.out.print("False");

有关我想要完成的事情的进一步信息:

为简单起见,假设只有整数(所以没有变量和小数位)。
运算符为:+, - ,*,/,%。
仅括号(所以没有括号或大括号)。

示例:

有效:

123  
1*2(3+4)%7  
3--4+5*-7  
13(12)+11-(7*15%(11-2)/4)  
(((((-99999)))))

无效

1+2)  
)5--  
3+*12  
)(++**//
(50)+12)

另外,如果可能,还可以包含有关正则表达式如何工作的简单说明吗?我对这个话题很陌生。我从概念上理解它,但在我的代码中实现它时遇到了麻烦。

1 个答案:

答案 0 :(得分:0)

正如几条评论所说,只是一个正则表达式匹配,你所要求的是不可能的。事实上,匹配平衡括号是一个经典的问题之一,这是一个简单的正则表达式无法解决的问题。只要您的数学表达式可以包含任意嵌套的括号,就不能使用正则表达式对其进行验证。

但是, 可以验证更小的语言,然后我们可以通过一些编码将其构建到您的语言的验证例程中。较小的语言就像您的语言,但只有一个变化:不允许使用括号。然后,语言中的有效表达式如下所示:

INTEGER OP INTEGER OP INTEGER OP .... OP INTEGER

另一种说法是" INTEGER后跟零个或多个OP INTEGER个序列"。这可以转换为正则表达式,如:

Pattern simpleLang = Pattern.compile("-?\\d+([-+*%/]-?\\d+)*");

所以-?\d+表示INTEGER[-+*%/]表示OP。好的,现在我们如何使用它?好吧,首先让我们修改它以在整数之间添加任意空格,并使模式为static,因为我们要将这个验证逻辑包装在一个类中:

static Pattern simpleLang = Pattern.compile("\\s*-?\\d+(\\s*[-+*%/]\\s*-?\\d+)*\\s*");

(虽然请注意,我们不允许在负号与其后面的数字之间留出空格,因此即使允许3 - - 4也不允许3 - -4

现在,为了验证完整的语言,我们需要做的是反复找到一个在最里面的括号级别的块(所以,一个块本身不包含parens,但是被一个开闭的paren对包围) ,验证parens中的东西是否与简单语言匹配,然后用一些整数替换该块(包括周围的parens),用空格包围,以便它被认为与周围的东西分开。所以逻辑是这样的:

  
      
  • expr进来的是11 - (7 * 15 % (11 - 2) / 4)
  •   
  • 最内侧括号内的块是11 - 2
  •   
  • 11 - 2是否符合简单语言?是的!
  •   
  • 用一些整数替换(11 - 2)。例如,使用1
  •   
  • expr现在是11 - (7 * 15 % 1 / 4)
  •   
  • 最内侧括号内的块是7 * 15 % 1 / 4
  •   
  • 7 * 15 % 1 / 4是否符合简单语言?是的!
  •   
  • 用一些整数替换(7 * 15 % 1 / 4)。例如,使用1
  •   
  • expr现在是11 - 1
  •   
  • 没有更多的parens,所以问:expr是否符合简单的语言?是的!
  •   

在代码中,这可以解决:

static Pattern simpleLang = Pattern.compile("\\s*-?\\d+(\\s*[-+*%/]\\s*-?\\d+)*\\s*");
static Pattern innerParen = Pattern.compile("[(]([^()]*)[)]");
public static boolean validateExpr(String expr) {
    while (expr.contains(")") || expr.contains("(")) {
        Matcher m = innerParen.matcher(expr);
        if (m.find()) {
            if (!simpleLang.matcher(m.group(1)).matches()) {
                return false;
            }
            expr = expr.substring(0,m.start()) + " 1 " + expr.substring(m.end());
        } else {
            // we have parens but not an innermost paren-free region
            // This implies mismatched parens
            return false;
        }
    }
    return simpleLang.matcher(expr).matches();
}

请注意,您调用了一个表达式"有效"这不会调用有效:即表达式13(12)+11-(7*15%(11-2)/4)。这将被视为无效,因为13和12之间没有运算符。如果您希望允许这种隐式乘法,最简单的方法是将(空格字符)添加为允许的运算符简单的语言,因此将simpleLang更改为:

static Pattern simpleLang = Pattern.compile("\\s*-?\\d+(\\s*[-+ *%/]\\s*-?\\d+)*\\s*");