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一度「コンパイル」することができます

  • codesplit メソッドを使用して文字列を分割する
  • トークンを HashSet に入れる (トークンがハッシュセットにあるかどうかのチェックはかなり高速です)。

もちろん、複数のコードがある場合、たとえばファイル名をキーとして持つマップなど、プログラムに適合した構造にそれらを簡単に格納できます。

于 2012-10-30T09:31:10.263 に答える
1

「プレーンな」文字列操作は、特にパターンをプリコンパイルできない場合に、正規表現よりも (ほとんど) 常に高速になります。

このようなものは、ニーズに合っていると仮定すると、(十分な大きさnameと文字列を使用して) かなり高速になります。codeCharacter.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;
}

彼が最初に私を正しい方向に向けてくれたので、受け入れられた答えはdystroyになります.Bart Kiersによる優れた答え、+1!

于 2012-10-30T10:36:10.587 に答える