Как прекратить Matcher.find (), когда он работает слишком долго? - PullRequest
7 голосов
/ 19 августа 2011

Хотите узнать о методах завершения длительных совпадений регулярных выражений (метод java matcher.find ()). Может быть, создание подкласса Matcher и добавление некоторой логики для завершения после x числа итераций?

По сути, я генерирую регулярные выражения с использованием генетического алгоритма, поэтому я не контролирую их. Затем я проверяю каждый из них на некоторый текст, чтобы увидеть, соответствуют ли они определенной целевой области текста.

Так что, поскольку я как бы генерирую эти регулярные выражения случайным образом, у меня происходят какие-то сумасшедшие вещи, и они съедают кучу процессорных ресурсов, и некоторым вызовам find () требуется некоторое время для завершения. Я бы предпочел просто убить их через некоторое время, но не уверен, что это лучший способ сделать это.

Так что, если у кого-то есть идеи, пожалуйста, дайте мне знать.

Ответы [ 6 ]

3 голосов
/ 19 августа 2011

Существует решение здесь , которое решит вашу проблему.(Это тот же вопрос, что и у вас.)

По сути, это CharSequence, который может замечать прерывания потока.

Код из этого ответа:

/**
 * CharSequence that noticed thread interrupts -- as might be necessary 
 * to recover from a loose regex on unexpected challenging input. 
 * 
 * @author gojomo
 */
public class InterruptibleCharSequence implements CharSequence {
    CharSequence inner;
    // public long counter = 0; 

    public InterruptibleCharSequence(CharSequence inner) {
        super();
        this.inner = inner;
    }

    public char charAt(int index) {
        if (Thread.interrupted()) { // clears flag if set
            throw new RuntimeException(new InterruptedException());
        }
        // counter++;
        return inner.charAt(index);
    }

    public int length() {
        return inner.length();
    }

    public CharSequence subSequence(int start, int end) {
        return new InterruptibleCharSequence(inner.subSequence(start, end));
    }

    @Override
    public String toString() {
        return inner.toString();
    }
}

Wrapваша строка с этим, и вы можете прервать поток.

1 голос
/ 15 февраля 2016

Просто покажи другое решение.

Вы можете использовать алгоритм NFA, который не чувствителен к вводу и в сотни раз быстрее, чем стандартная библиотека Java.

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

Вы можете ознакомиться с введением здесь: Соответствие регулярных выражений может быть простым и быстрым (но медленным в Java, Perl, PHP, Python, Ruby, ...)

Я также ответил на аналогичный вопрос более подробно здесь: Отмена длительного выполнения регулярного выражения?

1 голос
/ 19 августа 2011

Наихудший сценарий, в котором люди могут кричать на меня:

Вы можете запустить сопоставление регулярных выражений в другом потоке, а если он выполняется слишком долго, вы можете thread.stop() его.

0 голосов
/ 19 августа 2011

Вам нужно использовать другой поток и останавливать его, когда у него заканчивается время.

Существует два способа остановки: Thread # stop () и Thread # interrupt ().

Использование Thread.stop () довольно опасно, и Matcher не отвечает на Thread.interrupt (ответ на прерывание является обязательным поведением).

НО есть действительно умное решение, некоторые детали здесь .Используйте предоставленный InterruptibleCharSequence (он оборачивает вашу строку и работает почти как один, НО добавляет поддержку Thread # interrupt ()), затем создайте свой собственный Callable, возвращающий все, что возвращает matcher.Каждый выполняемый модуль теперь может быть выполнен с использованием комбо FutureTask / ThreadPool, и вы можете получить результат с любым временем ожидания:

Boolean result = myMatchingTask().get(2, TimeUnit.SECONDS)

Если вы находитесь в среде Java EE, вы можете пропустить сложную часть, простоиспользуйте вызовы InterruptipleCharSequence и @Asynchronous.

Если это звучит загадочно, попросите подробности.

0 голосов
/ 19 августа 2011

На вашем месте я бы создал свой собственный класс, который я поместил бы между моим приложением и библиотекой, которую вы используете для сопоставления, и реализовал бы такие методы, как «прерывание», которые вам нужны для уничтожения потока, и управления соответствием. таким образом.

0 голосов
/ 19 августа 2011

Одним из возможных решений, которое имеет приятную особенность в том, что он не блокирует основной поток, было бы создание «соответствия» в отдельном потоке.Вы можете создать персонализированный Callable, который возвращает null после истечения срока / порога или результата "соответствия", если он успешен.

...