Java: Как определить, почему не удается сопоставить шаблон с регулярным выражением? - PullRequest
10 голосов
/ 18 апреля 2011

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

Например, скажем, у меня есть шаблон "N {1,3} Y". Я сопоставляю его со строкой "NNNNY". Я хотел бы знать, что это не удалось, потому что было слишком много Ns. Или, если я сопоставлю его со строкой «XNNY», я хотел бы знать, что это не удалось, поскольку в строке был недопустимый символ «X».

При взгляде на API пакета регулярных выражений Java (java.util.regex), дополнительная информация кажется доступной из класса Matcher только после успешного совпадения.

Есть ли способ решить эту проблему? Или регулярное выражение даже вариант в этом сценарии?

Ответы [ 4 ]

9 голосов
/ 18 апреля 2011

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

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

2 голосов
/ 19 апреля 2011

Это может сработать, но я не знаю, так ли это вам нужно.

Когда вы используете matches, произойдет сбой, если вся последовательность не совпадает, но вы все равно можете использовать find, чтобы увидеть, содержит ли остальная часть последовательности шаблон, и, таким образом, понять, почему он потерпел неудачу:

import java.util.regex.*;
import static java.lang.System.out;
class F { 
    public static void main( String ... args ) { 
        String input = args[0];
        String re = "N{1,3}Y";
        Pattern p = Pattern.compile(re);
        Matcher m = p.matcher(input);
        out.printf("Evaluating: %s on %s%nMatched: %s%n", re, input, m.matches() );
        for( int i = 0 ; i < input.length() ; i++ ) { 
           out.println();
           boolean found = m.find(i);
           if( !found ) { 
               continue;
           }
           int s = m.start();
           int e = m.end();
           i = s;
           out.printf("m.start[%s]%n"
                     +"m.end[%s]%n"
                     +"%s[%s]%s%n",s,e,
                     input.substring(0,s), 
                     input.substring(s,e), 
                     input.substring(e) );
        }

    }
}

Вывод:

C:\Users\oreyes\java\re>java F NNNNY
Evaluating: N{1,3}Y on NNNNY
Matched: false

m.start[1]
m.end[5]
N[NNNY]

m.start[2]
m.end[5]
NN[NNY]

m.start[3]
m.end[5]
NNN[NY]


C:\Users\oreyes\java\re>java F XNNY
Evaluating: N{1,3}Y on XNNY
Matched: false

m.start[1]
m.end[4]
X[NNY]

m.start[2]
m.end[4]
XN[NY]

В первом выводе: N[NNNY] вы можете указать, где слишком много N, во втором: X[NNY] присутствовал X.

Вот другой вывод

C:\Users\oreyes\java\re>java F NYXNNXNNNNYX
Evaluating: N{1,3}Y on NYXNNXNNNNYX
Matched: false

m.start[0]
m.end[2]
[NY]XNNXNNNNYX

m.start[7]
m.end[11]
NYXNNXN[NNNY]X

m.start[8]
m.end[11]
NYXNNXNN[NNY]X

m.start[9]
m.end[11]
NYXNNXNNN[NY]X

Шаблон есть, но все выражение не совпадает.

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

совпадения похожи на /^YOURPATTERNHERE$/

lookAt похожи на /^YOURPATTERNHERE/

находка похожа на /YOURPATTERNHERE/

Надеюсь, это поможет.

1 голос
/ 18 апреля 2011

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

Итак, короче говоря, нет.

0 голосов
/ 19 апреля 2011

Для простых выражений, таких как "N {1,3} Y", вы найдете решение без инструментов самостоятельно. Но для более сложных выражений мой опыт подсказывает:

  • разбить большие выражения на более мелкие и протестировать их независимо.
  • , поскольку вы хотите получать быструю обратную связь, вы можете использовать интерактивную оболочку, такую ​​как Beanshell, для быстрого тестирования некоторых строк и шаблонов без большой компиляции, общедоступной статической пустоты main (bla ...) и так далее. Или попробуйте scala для этой задачи. Sed - еще один мощный инструмент для использования регулярных выражений, но в синтаксисе есть небольшие различия, которые могут привести к новым ошибкам.
  • Зачастую маскировка является проблемой. Поскольку обратная косая черта требует другой обратной косой черты, может быть преимуществом чтение выражения из JTextField, где вам не нужно так много маскировать.
  • Напишите небольшую среду тестирования для своих выражений, в которую вы можете легко помещать свои выражения, тестировать строки, возможно создавать автоматические тестовые данные и получать визуальную обратную связь.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...