Какой самый быстрый способ поиска подстроки в Java?

1

Я хочу понять проблемы производительности, которые могут возникнуть при выполнении поиска подстроки в Java. Я знаю два встроенных метода поиска подстроки в Java.

1. String.indexOf()

Насколько я понимаю, этот метод использует алгоритм грубой силы подстрочного поиска, поэтому его сложностью является O (nm), где n и m - длины строки и шаблона.

2. Используйте шаблон и контрольную точку

Я ничего не знаю о том, как реализуются алгоритмы регулярного выражения и об их сложности.

Поэтому вопросы:

1) Какой из этих методов предпочтительнее с точки зрения производительности?

2) Какова сложность поиска в регулярном выражении? Это зависит от самого регулярного выражения?

  • 1
    Aho-Corasick - лучший выбор, если вы действительно обеспокоены скоростью
  • 1
    Бойер-Мур с оптимизациями оказался в линейном времени в худшем случае. Конечно, такой вид ... побеждает цель вопроса с точки зрения того, что представлено. Вы хотите самый быстрый способ поиска подстроки, используя только эти инструменты? Какие подстроки вы ищете? Не могли бы вы привести примеры ввода и ожидаемого результата?
Показать ещё 15 комментариев
Теги:
string
algorithm
substring

1 ответ

1
Лучший ответ

Честно говоря, если вы заботитесь о худшем случае, JNI в собственный код, который вызывает вашу стандартную библиотечную функцию strstr. Хорошо реализованная strstr, как и в последних версиях glibc, имеет линейное наихудшее время работы и постоянное использование наихудшего пространства. Я считаю, что glibc strstr может делать Boyer-Moore-подобные длинные прыжки через текст. Стандартные библиотеки C поддерживаются людьми, которые умеют писать и поддерживать хорошие и универсальные библиотеки и практиковать свои ремесла. То же самое нельзя сказать о стандартной библиотеке классов Java.

Вам нужно будет превратить строку Java UTF-16 в нечто подходящее для strstr, например строку UTF-8. Вам также придется обрабатывать встроенные нулевые байты в строке UTF-8 изящно. Помимо этого, вы воспользуетесь преимуществами хорошо написанной и ухоженной библиотеки.

Java выполняет поиск регулярных выражений (для этого конкретного случая) с использованием строкового поиска Boyer-Moore, взломанного в наивную реализацию регулярного выражения. Компиляция Pattern только с вашей строкой приведет к тому, что Matcher будет работать относительно хорошо. Обратите внимание, однако, что это НЕ распространяется на все, кроме поиска строк в библиотеке regex; вы по-прежнему придерживаетесь наивной реализации регулярного выражения, которая отступает и все, если вы кормите это нетривиальное регулярное выражение.

В качестве доказательства того, почему вы не должны использовать регулярное выражение Java для реальных регулярных выражений, я представлю вам следующее:

public class regex {
  public static void main(String[] args) throws Exception {
    String haystack = "ab";
    String needle = "abab?.*";
    for (int i = 0; i < 7; i++) haystack = haystack + haystack;
    for (int i = 0; i < 4; i++) needle = needle + needle;
    System.out.println(haystack.length() + " " + needle.length());
    long before = System.currentTimeMillis();
    System.out.println(Pattern.matches(needle, haystack));
    long after = System.currentTimeMillis(); // long after indeed...
    System.out.println(after - before);
  }
}

Это поиск в стоге сена в 256 символов для регулярного выражения иглы (это честное регулярное выражение, которое вы узнали в классе компиляторов) в 112 символов. Это займет около 24 секунд, чтобы завершить работу на моей машине.

  • 1
    /abab?.*abab?.*abab?.*.../ уничтожит любую машину ...
  • 1
    @Unihedron: это действительно не будет. Пойдите, возьмите любую вступительную книгу компиляторов и прочитайте о том, как реализовать регулярные выражения. Или посмотрите на реализацию регулярных выражений Русса Кокса по адресу swtch.com/~rsc/regexp .
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню