Я использовал java.util.regex.* классы для Регулярного выражения в Java и всей пользе до сих пор. Но сегодня у меня есть другое требование. Например, полагайте, что шаблон "aabb". Теперь, если входная строка будет aa, то это не будет определенно соответствовать, однако существует все еще возможность, что, если я добавляю bb, это становится aabb, и это соответствует. Однако, если я запустил бы с cc, независимо от того, что я добавляю его, никогда не будет соответствовать.
Я исследовал класс Pattern и Matcher, но не нашел способа достигнуть этого.
Вход прибудет от пользователя, и система должны ожидать, пока соответствия шаблона или это никогда не будут соответствовать независимо ни от какого входа далее.
Какая-либо подсказка?
Спасибо.
Один из способов сделать это - разобрать ваше регулярное выражение на последовательность подрегулярных выражений, а затем собрать их таким образом, чтобы вы могли выполнять частичные совпадения; например «ab c» имеет 3 подрегегекса «a», «b » и «c», которые затем можно собрать как «a (b * (c)?)?».
Ситуация усложняется, когда входное регулярное выражение содержит чередование и группы, но должен работать тот же общий подход.
Проблема с этим подходом состоит в том, что результирующее регулярное выражение является более сложным и потенциально может привести к чрезмерному отслеживанию с возвратом для сложных входных регулярных выражений.
Итак, вы хотите знать, не совпадает ли String s с регулярным выражением, а может ли совпадать более длинная строка, начинающаяся с s? Извините, регулярные выражения не могут вам помочь, потому что у вас нет доступа к внутреннему состоянию сопоставителя; вы получаете только логический результат и любые группы, которые вы определили, поэтому вы никогда не узнаете , почему совпадение не удалось.
Если вы хотите взломать библиотеки JDK, вы можете расширить (или, возможно, разветвить) java.util.regex
и предоставить дополнительную информацию о процессе сопоставления. Если совпадение не удалось, потому что вход был «израсходован», ответ будет истина ; если он не удался из-за распознавания символов или других проверок, он будет ложным . Это кажется большой работой, потому что ваша проблема полностью противоположна тому, что должны делать регулярные выражения.
Другой вариант: может быть, вы можете просто переопределить задачу, чтобы обрабатывать ввод как регулярное выражение и сопоставлять aabb с * aa. **? Однако вы должны быть осторожны с метасимволами регулярных выражений.
Если вы сделаете каждый символ регулярного выражения необязательным и уменьшите множественность ограничения, вы как бы получаете то, что хотите. Пример: если у вас есть соответствующий шаблон «aa (abc) + bbbb», у вас может быть шаблон «возможное совпадение» 'a? A? (A? B? C?) * B? B? B? B?'.
Этот механический способ создания шаблона возможного совпадения не распространяется на сложные конструкции, такие как прямые и обратные ссылки.
В приведенном вами примере вы можете попытаться использовать анти-шаблон для дисквалификации недействительных результатов. Например, «^ [^ a]» сообщит вам, что вы вводите «c ...» не может соответствовать вашему примеру шаблона «aabb».
В зависимости от вашего шаблона вы можете разбить его на более мелкие шаблоны, чтобы проверить и использовать несколько сопоставлений, а затем установить их границы, когда происходит одно совпадение, и вы переходите к следующему. Этот подход может работать, но если ваш шаблон сложен и может иметь подчасти переменной длины, вы можете в конечном итоге переопределить часть сопоставления в своем собственном коде, чтобы настроить возможные границы сопоставления, чтобы сделать его более или менее жадным. Общая идея псевдокода для этого будет следующая:
boolean match(String input, Matcher[] subpatterns, int matchStart, int matchEnd){
matcher = next matcher in list;
int stop = matchend;
while(true){
if matcher.matches input from matchstart -> matchend{
if match(input, subpatterns, end of current match, end of string){
return true;
}else{
//make this match less greedy
stop--;
}
}else{
//no match
return false;
}
}
}
Затем вы могли бы объединить эту идею с анти-шаблонами и иметь анти-подшаблоны, и после каждого совпадения подшаблонов вы проверяете следующий анти-шаблон, если он соответствует, вы знаете, что не удалось, в противном случае продолжить поиск по шаблону. Вы, вероятно, захотите вернуть что-то вроде перечисления вместо логического (например, ALL_MATCHED, PARTIAL_MATCH, ANTI_PATTERN_MATCH, ...)
Опять же, в зависимости от сложности вашего фактического шаблона, который вы пытаетесь сопоставить, написав соответствующие подшаблоны / анти-шаблон может быть трудным, если не невозможным.
Вы могли бы сделать это с помощью конечного автомата ( http://en.wikipedia.org/wiki/State_machine ) . Ваши состояния / переходы должны представлять действительный ввод и одно состояние ошибки. Затем вы можете передать в конечный автомат по одному символу (возможно, подстроке в зависимости от ваших данных) за раз. В любой момент вы можете проверить, находится ли ваш конечный автомат в состоянии ошибки. Если он не в состоянии ошибки, значит, вы знаете, что будущий ввод все еще может совпадать. Если он находится в состоянии ошибки, значит, вы знаете, что что-то ранее не удалось, и любой будущий ввод не сделает строку действительной.
Вам следовало бы более внимательно изучить API-интерфейс Matcher; метод hitEnd ()
работает точно так, как вы описали:
import java.util.regex.*;
public class Test
{
public static void main(String[] args) throws Exception
{
String[] ss = { "aabb", "aa", "cc", "aac" };
Pattern p = Pattern.compile("aabb");
Matcher m = p.matcher("");
for (String s : ss) {
m.reset(s);
if (m.matches()) {
System.out.printf("%-4s : match%n", s);
}
else if (m.hitEnd()) {
System.out.printf("%-4s : partial match%n", s);
}
else {
System.out.printf("%-4s : no match%n", s);
}
}
}
}
output:
aabb : match
aa : partial match
cc : no match
aac : no match
Насколько мне известно, Java - единственный язык, который предоставляет эту функциональность.Также существует метод requireEnd ()
, который сообщает вам, может ли дополнительный ввод превратить совпадение в несоответствие, но я не думаю, что это актуально в вашем случае.
Оба метода были добавлены для поддержки класса Scanner, поэтому он может применять регулярные выражения к потоку, не требуя считывания всего потока в память.