Подтвердить что ты не робот

Как выполнить частичное совпадение с java.util.regex. *?

Я использую классы java.util.regex. * для регулярного выражения в Java и все до сих пор хорошо. Но сегодня у меня другое требование. Например, рассмотрим шаблон как "абаб". Теперь, если входной String является aa, он определенно не будет соответствовать, однако есть еще вероятность, что если я добавлю bb, он станет aabb, и он будет соответствовать. Однако, если бы я начал с cc, независимо от того, что я добавляю, он никогда не будет соответствовать.

Я изучил класс Pattern и Matcher, но не нашел способа добиться этого.

Вход будет поступать от пользователя, и система должна ждать, пока шаблон не будет соответствовать, или он никогда не будет соответствовать независимо от ввода.

Любая подсказка?

Спасибо.

4b9b3361

Ответ 1

Вам следовало бы более внимательно изучить 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);
      }
    }
  }
}

выход:

aabb : match
aa   : partial match
cc   : no match
aac  : no match

Насколько я знаю, Java является единственным языком, который предоставляет эту функциональность. Также существует метод requireEnd(), который говорит вам, что больше ввода может превратить совпадение в несоответствие, но я не думаю, что это имеет значение в вашем случае.

Оба метода были добавлены для поддержки класса Scanner, поэтому он может применять регулярные выражения к потоку, не требуя, чтобы весь поток считывался в память.

Ответ 2

Pattern p = Pattern.compile(expr);
Matcher m = p.matcher(string);
m.find();

Ответ 3

Итак, вы хотите знать, не соответствует ли строка s регулярному выражению, но может ли быть более длинная строка, начинающаяся с s, которая будет соответствовать? Извините, Regexes не может помочь вам там, потому что у вас нет доступа к внутреннему состоянию соединителя; вы получаете только логический результат и любые группы, которые вы определили, поэтому вы никогда не знаете, почему совпадение не получилось.

Если вы готовы взломать библиотеки JDK, вы можете расширить (или, возможно, fork) java.util.regex и предоставить дополнительную информацию о процессе сопоставления. Если совпадение не получилось, потому что вход был "использован", ответ был бы правдой; если он потерпел неудачу из-за дискриминации характера или других проверок, это было бы неверно. Это похоже на большую работу, потому что ваша проблема полностью противоположна тому, что должны делать регулярные выражения.

Другой вариант: возможно, вы можете просто переопределить задачу, чтобы вы могли рассматривать ввод как регулярное выражение и сопоставлять aabb с * aa. **? Однако вы должны быть осторожны с метасимволами регулярных выражений.

Ответ 4

В приведенном примере вы можете попытаться использовать анти-шаблон для дисквалификации недопустимых результатов. Например, "^ [^ 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,...)

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

Ответ 5

Один из способов сделать это - проанализировать ваше регулярное выражение в последовательности подреггексов, а затем собрать их таким образом, чтобы вы могли выполнять частичные совпадения; например "abc" имеет 3 подрежима "a", "b" и "c", которые затем можно собрать в виде "a (b * (c)?)?".

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

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

Ответ 6

Если вы производите каждый символ регулярного выражения и расслабляете ограничения множественности, вы можете получить то, что хотите. Например, если у вас есть соответствующий шаблон "aa (abc) + bbbb", вы можете иметь шаблон "возможного соответствия" a? A? (A? B? C?) * B? B? B? B? '.

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

Ответ 7

Возможно, вы сможете выполнить это с помощью конечного автомата (http://en.wikipedia.org/wiki/State_machine). Пусть ваши состояния/переходы представляют собой допустимый вход и одно состояние ошибки. Затем вы можете подать конечный автомат на один символ (возможно, подстроку в зависимости от ваших данных) одновременно. В любой момент вы можете проверить, находится ли ваш конечный автомат в состоянии ошибки. Если он не находится в состоянии ошибки, вы знаете, что будущий ввод все равно может совпадать. Если он находится в состоянии ошибки, то вы знаете что-то ранее не удалось, и любой будущий ввод не сделает строку действительной.