Java中的有效括号

时间:2016-03-21 13:37:05

标签: java regex replaceall

代码:

public static void main(String[] args) {
    Arrays.asList("a+(b*c)-2-a", "(a+b*(2-c)-2+a)*2", "(a*b-(2+c)", "2*(3-a))", ")3+b*(2-c)(")
            .stream().forEach((expression) -> {
                if (replaceAll(expression, "[(]") == replaceAll(expression, "[)]")) {
                    System.out.println("correct");
                } else {
                    System.out.println("incorrect");
                }
            });
}

private static int replaceAll(String word, String regex) {
    int count = word.length() - word.replaceAll(regex, "").length();
    return count;
}

我必须检查表达式是否有效。确定表达式是否有效的是括号。如果它是自闭的,则有效,否则不是。

我的代码几乎正确,正在打印:

correct
correct
incorrect
incorrect
correct

但它必须打印

correct
correct
incorrect
incorrect
incorrect -> the last expression isn't valid.

3 个答案:

答案 0 :(得分:4)

您不仅需要检查开括号的数量是否与已关闭的数量相匹配,而且还需要检查每个右括号是否在打开一个不关闭"关闭"然而:

static boolean checkParentheses(String s) {
     int opened = 0;
     for (int i = 0; i < s.length(); i++) {
         if (s.charAt(i) == '(')
             opened++;
         else if (s.charAt(i) == ')') {
             if (opened == 0)    // means that all parentheses are "closed" yet
                return false;
             opened--;
         }
     }
     return opened == 0;
}

如果您严格需要参与正则表达式,请执行以下操作:

static boolean checkParentheses(String s) {
    // capture a text starting with one opening parenthesis, 
    // ending with one closing and having no parentheses inside
    Pattern p = Pattern.compile("\\([^()]*\\)");  
    Matcher m;
    while ((m = p.matcher(s)).find())
       s = m.replaceAll("");
    return !(s.contains("(") || s.contains(")"));
}

答案 1 :(得分:1)

你的问题是只计算括号是不够的;你还需要找到一个&#39;)&#39;太早了。例如&#34;)(&#34;即使有相同数量的开括号和右括号也无效。

一种方法是保持计数。从零开始。每当您看到&#39;(&#39;,count++。每次看到&#39;)&#39;,count--

减量后,if(count<0)输入无效。

在输入结束时,if(count!0)输入无效。

有人指出,这不能在一个正则表达式中完成。这是因为正则表达式代表有限状态机。 count原则上可以无限增加。

如果选择最大嵌套深度,可以编写正则表达式进行检查。例如,最大深度为3:

x*(<x*(<x*(<x*>)*x*>)*x*>)*x*

(我已经使用&#39; x&#39;而不是任意字符,为了便于阅读。将其替换为[^<>]以实际匹配其他字符。我还使用了{{为了便于阅读,再次使用{}}}而不是<>。此处的\(\)用于分组。)。

你可以通过用()替换中间的x*来让它更深入地工作 - 但是你永远不能制作一个不会在某个深度停止工作的正则表达式

另一种方法更接近真正的语句解析器对嵌套结构的处理方式:recurse。像(伪代码)的东西:

x*(<x*>)*x*

此处def consumeBlock() { switch(next char) case end-of-input throw error -- reached end of input inside some parentheses case '(' consumeBlock() -- go down a nesting level break; case ')' return -- go up a nesting level default It's an uninteresting character. Do nothing. (a real parser compiler would do something more interesting) } 假设您刚刚消费了一个&#39;(&#39;并且您打算在其配对之前阅读。

您的一些输入不是以&#39;(&#39;开头,首先附加&#39;以及#39;到最后,作为一对&#34;沉默&#34; &#39;)&#39;你说它已经被消耗了。

伪代码已经显示,如果你点击输入结束的中间块,它的输入无效。此外,如果您在consumeBlock()的顶级电话回复时没有输入结束,则输入无效。

答案 2 :(得分:0)

您可以通过char查询char并使用计数器告诉语句中的括号级别。

boolean valid = true;
int level = 0;
for(int i=0; i < expr.length(); i++) {
    if(expr.charAt(i) == '(') level++;
    if(expr.charAt(i) == ')') level--;
    if(level < 0) { // ) with no (
        valid = false; 
        break;
    }
}
if(level > 0) valid = false; // ( with no )
return valid; // true if level returned to 0