在Java中匹配外部括号太慢

时间:2013-06-16 23:51:31

标签: java performance

我需要选择两个外括号之间的所有文本。由于无法确保正则表达式选择匹配括号,因此我编写了以下代码:

public static String getContentBetweenCorresponding(String s, char left, char right) {
    int pos = s.indexOf(left);
    if ( pos > -1 ) {
        int start = pos;
        int openCount = 0;
        while ( pos < s.length() ) {
            char currentChar = s.charAt(pos);
            if ( currentChar == right ) {
                if ( openCount > 1 ) // if openCount == 1 then correct one 
                    openCount--;
                else
                    return s.substring(start + 1, pos);
            } else if ( currentChar == left )
                openCount++;
            pos++;
        }
    }
    return null;
}

有效。然而,它是无助的慢。我怎样才能加快速度?这个方法需要5s才能完成我的应用程序的瓶颈。

提前多多感谢!

编辑: 我想要做的是在匹配括号之间获取文本。

getContentBetweenCorresponding("bla{{{blubb}}}}}}", '{', '}')

应该返回

"{{blubb}}"

3 个答案:

答案 0 :(得分:2)

您编写的方法没有任何明显的低效率。我的猜测实际上问题在于以下其中一个:

  1. 当您可以调用一次并存储结果时,您可能会多次为同一个字符串s调用此函数。
  2. 您可能会将非常大的字符串传递给此方法,并且字符串的开头与结束括号之间的距离非常大。
  3. 如果预计{}之间的距离对于您的实际输入很大,则可以重写方法以使用indexOf直接查找leftright代替为每个角色测试charAt。在这种情况下,调用indexOf的次数比调用charAt少得多,而最外侧括号之间的字符串中的字符将至少检查{{1}的内部实现的两倍。可能会超过JIT使用indexOf所做的表现。

答案 1 :(得分:1)

这看起来并不太糟糕。你确定这种方法会导致性能问题吗?

您可以尝试紧密循环,以找到下一个打开,关闭或结束。也许转换为char数组而不是charAttoCharArray或更好getChars)。它至少是用较小的方法获得更好结果的情况。

在更新版本的Java中,substring将复制支持数组,这种情况不常发生。

所以这就是我如何在没有进行任何基准测试的情况下编写它的性能(!)(可能修改了界面而不是创建String,甚至可以修改一个) -

public static String betweenMatchedBrackets(
     String str, char open, char close
) {
    int start = str.indexOf(open);
    if (start == -1) {
        return null;
    }

    ++start;
    int strLen = str.length();
    char[] cs = new char[strLen-start]; // Assume typically much of string
    strLen.getChars(start, len, cs, 0);

    int foundLen = endingBracket(cs, open, closed);
    return foundLen != cs.length ? str.substring(start, start+foundLen) : null;
}
private static int endingBracket(char cs, char open, char closed) {
    int depth = 1;
    int i = 0;
    for (; depth != 0 && i != cs.length; ) {
        i = nextInteresting(cs, i, open, close);
        if (i != cs.length) {
            char c = cs[i];
            depth += c==open ? 1 : -1;
        }
    }
    return int;
}
private static int nextInteresting(char[] cs, int off, char open, char close) {
    for (; off != cs.length && cs[off] != open && cs[off] != close; ++off) {
    }
    return off;
}

(未进行基准测试或编译。)

答案 2 :(得分:-2)

我认为你不需要编写自己的方法。您可以使用Java正则表达式将括号括起来的字符串。下面的示例代码将为您提供正常括号中间的字符串

    String str = "Hello (big) world";
    Pattern pattern = Pattern.compile("\\((\\w+)\\)");
    Matcher matcher = pattern.matcher(str);
    matcher.find();

            // result below is "big"
    String result = matcher.group(1);