优化基于正则表达式的查找功能

时间:2012-10-30 09:30:04

标签: java regex

我有以下功能。

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

在我的代码中被称为数千次,并且是我的程序花费最多时间的函数。有没有办法让这个函数更快,或者它已经快到可以了?

3 个答案:

答案 0 :(得分:4)

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

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

如果你需要检查单词边界,但是,正如我想的那样,你有一个很大的code经常搜索,你可以“编译”code一次

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

当然,如果你有多个代码,很容易将它们存储在适合你程序的结构中,例如在具有文件名密钥的地图中。

答案 1 :(得分:1)

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

这样的事情会快得多(namecode字符串足够大),假设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));
}

答案 2 :(得分: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!