简体   繁体   English

用于验证数学表达式的正则表达式

[英]Regular Expression to Validate a Math Expression

I'm trying to determine if a given input is a valid Math Expression. 我正在尝试确定给定的输入是否为有效的数学表达式。 This is the current code I've come up with, but it only ever returns true if Input is a single integer (eg 100, 200, 5, 7). 这是我目前想出的代码,但是只有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");

Further information on what I'm trying to accomplish: 有关我要完成的工作的更多信息:

For simplicity's sake assume integers only (so no variables and decimal places). 为简单起见, 假设整数 (因此,不包含变量和小数位)。
Operators are: +, -, *, /, %. 运算符为:+,-,*,/,%。
Parenthesis only (so no brackets or braces). 仅带括号(因此没有括号或花括号)。

Examples: 例子:

Valid: 有效:

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

Not Valid 无效

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

Also, if possible, could a simple explanation on how the Regex works be included as well? 另外,如果可能的话,是否还可以包含有关Regex工作原理的简单解释? I'm quite new to the topic. 我对这个话题很陌生。 I understand it conceptually but have trouble implementing it in my code. 我从概念上理解它,但是在我的代码中难以实现。

As several comments say, what you ask for is impossible with just a regex match. 如几条评论所述, 使用正则表达式匹配是您无法要求的。 In fact, matching balanced parentheses is one of the classic "problems that cannot be solved by a simple regular expression". 实际上,匹配的平衡括号是经典的“简单的正则表达式无法解决的问题”之一。 As long as your mathematical expressions can contain arbitrarily nested parentheses, you can't validate it with a regex. 只要您的数学表达式可以包含任意嵌套的括号,就不能使用正则表达式对其进行验证。

However, it is possible to validate a smaller language, and we can then build that up into a validation routine for your language with a little bit of coding. 然而,就可以验证一个较小的语言,然后我们可以构建成与编码的一点点您的语言的验证程序。 The smaller language is just like your language but with one change: no parentheses allowed . 较小的语言与您的语言一样,但有一个变化: 不允许使用括号 Then, valid expressions in the language look like this: 然后,该语言中的有效表达式如下所示:

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

Another way to say that is "an INTEGER followed by zero or more OP INTEGER sequences". 另一种说法是“一个INTEGER后跟零个或多个OP INTEGER序列”。 This can be translated into a regex, as: 可以将其转换为正则表达式,例如:

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

So -?\\d+ means INTEGER , and [-+*%/] means OP . 所以-?\\d+表示INTEGER[-+*%/]表示OP Okay, now how do we use this? 好的,现在我们该如何使用呢? Well, first off let's modify it to add arbitrary spaces in there between integers, and make the pattern a static , because we're going to wrap this validation logic up in a class: 好吧,首先让我们对其进行修改,以在整数之间添加任意空格,并使模式成为static ,因为我们将把此验证逻辑包装在一个类中:

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

(Though note that we don't allow a space between a negative sign and the number that follows it, so 3 - - 4 isn't allowed, even though 3 - -4 is allowed) (但请注意,我们不允许一个负号和它后面的号码之间的空格,所以3 - - 4是不允许的,即使3 - -4是允许的)

Now, to validate the full language, what we need to do is repeatedly find a chunk that's at the innermost parenthesized level (so, a chunk containing no parens itself but surrounded by a open-close paren pair), validate that the stuff inside the parens matches the simple language, and then replace that chunk (including the surrounding parens) with some integer, surrounded by spaces so that it's considered separate from the surrounding stuff. 现在,要验证完整语言,我们需要做的是重复查找位于最内括号级别的块(因此,一个块本身不包含任何括号,但被一个开闭括号对包围),请验证parens与简单语言匹配,然后用一些整数(用空格包围)替换该块(包括周围的paren),以便将其与周围的东西分开。 So the logic is something like this: 所以逻辑是这样的:

  • expr coming in is 11 - (7 * 15 % (11 - 2) / 4) expr进来是11 - (7 * 15 % (11 - 2) / 4)
  • Innermost parenthesized chunk is 11 - 2 最里面的括号块是11 - 2
  • Does 11 - 2 match the simple language? 请问11 - 2比赛的简单的语言? Yes! 是!
  • replace (11 - 2) with some integer. 用一些整数替换(11 - 2) For example, with 1 . 例如,使用1
  • expr is now 11 - (7 * 15 % 1 / 4) expr现在是11 - (7 * 15 % 1 / 4)
  • Innermost parenthesized chunk is 7 * 15 % 1 / 4 最里面带括号的块是7 * 15 % 1 / 4
  • Does 7 * 15 % 1 / 4 match the simple language? 7 * 15 % 1 / 4与简单语言匹配? Yes! 是!
  • replace (7 * 15 % 1 / 4) with some integer. 用一些整数替换(7 * 15 % 1 / 4) For example, with 1 . 例如,使用1
  • expr is now 11 - 1 expr现在是11 - 1
  • No more parens, so ask: does expr match the simple language? 不用了,请问: expr与简单语言匹配? Yes! 是!

In code this works out to: 在代码中,它可以做到:

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();
}

Note that there is one expression you called "valid" that this will not call valid: namely, the expression 13(12)+11-(7*15%(11-2)/4) . 请注意,有一个您称为“有效”的表达式,它不会称为有效:即表达式13(12)+11-(7*15%(11-2)/4) This will be considered invalid because there is no operator between 13 and 12. If you wish to allow that sort of implicit multiplication, the easiest way to do it is to add 这将被视为无效,因为在13和12之间没有运算符。如果您希望允许这种隐式乘法,最简单的方法是添加 (the space character) as an allowed operator in the simple language, so change simpleLang to: (空格字符)作为简单语言中允许的运算符,因此请将simpleLang更改为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM