Как узнать, может ли строка соответствовать регулярному выражению, добавив больше символов - PullRequest
0 голосов
/ 30 октября 2018

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

Моя цель - найти способ узнать, может ли строка, читаемая из входного потока, по-прежнему соответствовать заданному шаблону регулярного выражения. Или, другими словами, читайте поток до тех пор, пока мы не получим строку, которая определенно не будет соответствовать такому шаблону, независимо от того, сколько символов вы добавите к нему.

Объявление минималистского простого метода для достижения этой цели может выглядеть примерно так:

boolean couldMatch(CharSequence charsSoFar, Pattern pattern);

Такой метод вернул бы true в случае, если charsSoFar все еще может соответствовать шаблону, если добавлены новые символы, или false, если у него вообще нет шансов сопоставить его даже с добавлением новых символов.

Чтобы привести более конкретный пример, скажем, у нас есть шаблон для чисел с плавающей точкой, например "^([+-]?\\d*\\.?\\d*)$".

При таком шаблоне couldMatch вернет true для следующего примера charsSoFar параметр:

"+"  
"-"  
"123"  
".24"  
"-1.04" 

И так далее, и тому подобное, потому что вы можете продолжать добавлять цифры ко всем этим, а также одну точку в трех первых.

С другой стороны, все эти примеры, полученные из предыдущего, должны возвращать false:

"+A"  
"-B"  
"123z"  
".24."  
"-1.04+" 

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

EDIT:

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

Сначала я объявляю следующий функциональный интерфейс:

public interface Matcher {
    /**
     * It will return the matching part of "source" if any.
     *
     * @param source
     * @return
     */
    CharSequence match(CharSequence source);
}

Тогда предыдущая функция будет переопределена как:

boolean couldMatch(CharSequence charsSoFar, Matcher matcher);

И (составленный) метод сопоставления для чисел с плавающей запятой может выглядеть следующим образом (обратите внимание, что в начале не поддерживается знак +, только -):

public class FloatMatcher implements Matcher {
    @Override
    public CharSequence match(CharSequence source) {
        StringBuilder rtn = new StringBuilder();

        if (source.length() == 0)
            return "";

        if ("0123456789-.".indexOf(source.charAt(0)) != -1 ) {
            rtn.append(source.charAt(0));
        }

        boolean gotDot = false;
        for (int i = 1; i < source.length(); i++) {
            if (gotDot) {
                if ("0123456789".indexOf(source.charAt(i)) != -1) {
                    rtn.append(source.charAt(i));
                } else
                    return rtn.toString();
            } else if (".0123456789".indexOf(source.charAt(i)) != -1) {
                rtn.append(source.charAt(i));
                if (source.charAt(i) == '.')
                    gotDot = true;
            } else {
                return rtn.toString();
            }
        }
        return rtn.toString();
    }
}

Внутри пропущенного тела для метода mightMatch он просто будет итеративно вызывать matcher.match () с новым символом, добавленным в конце параметра источника, и возвращать истину, в то время как возвращенный CharSequence равен параметру источника, и ложь как только все по-другому (это означает, что последний добавленный символ сломал матч).

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Вы можете сделать это так же просто, как

boolean couldMatch(CharSequence charsSoFar, Pattern pattern) {
    Matcher m = pattern.matcher(charsSoFar);
    return m.matches() || m.hitEnd();
}

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

Или, как документация говорит:

Возвращает истину, если поисковый механизм достиг конца ввода во время последней операции сопоставления, выполненной этим сопоставителем.

Когда этот метод возвращает true, возможно, что большее количество входных данных изменило бы результат последнего поиска.

Это также используется классом Scanner внутри, чтобы определить, должен ли он загружать больше данных из исходного потока для операции сопоставления.

Используя метод выше с вашими образцами данных, вы получите

Pattern fpNumber = Pattern.compile("[+-]?\\d*\\.?\\d*");
String[] positive = {"+", "-", "123", ".24", "-1.04" };
String[] negative = { "+A", "-B", "123z", ".24.", "-1.04+" };
for(String p: positive) {
    System.out.println("should accept more input: "+p
                      +", couldMatch: "+couldMatch(p, fpNumber));
}
for(String n: negative) {
    System.out.println("can never match at all: "+n
                      +", couldMatch: "+couldMatch(n, fpNumber));
}
should accept more input: +, couldMatch: true
should accept more input: -, couldMatch: true
should accept more input: 123, couldMatch: true
should accept more input: .24, couldMatch: true
should accept more input: -1.04, couldMatch: true
can never match at all: +A, couldMatch: false
can never match at all: -B, couldMatch: false
can never match at all: 123z, couldMatch: false
can never match at all: .24., couldMatch: false
can never match at all: -1.04+, couldMatch: false

Конечно, это ничего не говорит о шансах превратить несоответствующий контент в совпадение. Вы по-прежнему можете создавать шаблоны, для которых ни один дополнительный символ никогда не сможет сравниться. Однако для обычных случаев использования, таких как числовой формат с плавающей запятой, это разумно.

0 голосов
/ 30 октября 2018

У меня нет конкретного решения, но вы могли бы сделать это с отрицаниями.

Если вы настроили шаблоны регулярных выражений в черном списке, которые определенно не соответствуют вашему шаблону (например, + с последующим символом), вы можете проверить их. Если регулярное выражение в черном списке возвращает true, вы можете прервать его.

Другая идея заключается в использовании негативных просмотров (https://www.regular -expressions.info / lookaround.html )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...