0

我有以下功能。

private boolean codeContains(String name, String code) {
    if (name == null || code == null) {
        return false;
    }

    Pattern pattern = Pattern.compile("\\b" + Pattern.quote(name) + "\\b");
    Matcher matcher = pattern.matcher(code);

    return matcher.find();
}

它在我的代码中被调用了数千次,并且是我的程序花费最多时间的函数。有没有办法让这个函数运行得更快,或者它已经尽可能快了?

4

3 回答 3

4

如果您不需要检查单词边界,您可以这样做:

private boolean codeContains(String name, String code) {
    return name != null && code != null && code.indexOf(name)>=0;
}

如果您需要检查单词边界,但我想是您的情况,您有一个code经常搜索的内容,您可以“编译”code一次

  • 使用 split 方法拆分code字符串
  • 将令牌放入哈希集中(检查令牌是否在哈希集中相当快)。

当然,如果您有多个代码,很容易将它们存储在适合您的程序的结构中,例如以文件名作为键的映射中。

于 2012-10-30T09:31:10.263 回答
1

“普通”字符串操作(几乎)总是比正则表达式更快,尤其是当您无法预编译模式时。

假设适合您的需求,这样的事情会更快(有足够大的name字符串code) :Character.isLetterOrDigit(...)

private boolean codeContains(String name, String code) {

    if (name == null || code == null || code.length() < name.length()) {
        return false;
    }

    if (code.equals(name)) {
        return true;
    }

    int index = code.indexOf(name);
    int nameLength = name.length();

    if (index < 0) {
        return false;
    }

    if (index == 0) {
        // found at the start
        char after = code.charAt(index + nameLength);
        return !Character.isLetterOrDigit(after);
    }
    else if (index + nameLength == code.length()) {
        // found at the end
        char before = code.charAt(index - 1);
        return !Character.isLetterOrDigit(before);
    }
    else {
        // somewhere inside
        char before = code.charAt(index - 1);
        char after = code.charAt(index + nameLength);
        return !Character.isLetterOrDigit(after) && !Character.isLetterOrDigit(before);
    }
}

一个小测试成功了:

@Test
public void testCodeContainsFaster() {

    final String code = "FOO some MU code BAR";

    org.junit.Assert.assertTrue(codeContains("FOO", code));
    org.junit.Assert.assertTrue(codeContains("MU", code));
    org.junit.Assert.assertTrue(codeContains("BAR", code));
    org.junit.Assert.assertTrue(codeContains(code, code));

    org.junit.Assert.assertFalse(codeContains("FO", code));
    org.junit.Assert.assertFalse(codeContains("BA", code));
    org.junit.Assert.assertFalse(codeContains(code + "!", code));
}
于 2012-10-30T10:07:46.413 回答
0

这段代码似乎做到了:

private boolean codeContains(String name, String code) {
    if (name == null || code == null || name.length() == 0 || code.length() == 0) {
        return false;
    }

    int nameLength = name.length();
    int lastIndex = code.length() - nameLength;

    if (lastIndex < 0) {
        return false;
    }

    for (int curr = 0; curr < lastIndex; ) {
        int index = code.indexOf(name, curr);
        int indexEnd = index + nameLength;

        if (index < 0 || lastIndex < index) {
            break;
        }

        boolean leftOk = index == curr ||
                index > curr && !Character.isAlphabetic(code.charAt(index - 1));

        boolean rightOk = index == lastIndex ||
                index < lastIndex && !Character.isAlphabetic(code.charAt(indexEnd));

        if (leftOk && rightOk) {
            return true;
        }

        curr += indexEnd;
    }

    return false;
}

公认的答案变得混乱,因为他是第一个为我指出正确方向的人,但巴特·基尔斯(Bart Kiers)的出色回答,+1!

于 2012-10-30T10:36:10.587 回答