Сбой шаблона отладки (regex) в Java (Android)

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

DLVRYrx = Pattern.compile("(\\d+\\s\\p{Letter}+\\s\\d+)\\s(\\d+(?:\\.\\d+)?)\\s(\\d+)");
Log.d(TAG, "* Regex matched " + DLVRYrx.matcher("01 Jan 01 60.9876 1234").groupCount() + " groups"); // prints 3 as expected in logcat
for (int i=19; i<(fields-6); i++) {
    final String DATAstr = values[i];
    try {
        Matcher Dmatch = DLVRYrx.matcher(DATAstr);
        String data1 = Dmatch.group(0);
    } catch (IllegalStateException e) {
        Log.e(TAG, "! Text ["+DATAstr+"] didn't match regex");
    }
}

Код создает исключение IllegalStateException в строке Dmatch.group(0). Вывод строки logcat из улова: «01 января 01 60,9876 1234», как указано выше.

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

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

Pattern P = Pattern.compile(DLVRYrxStr);
if(!DATAstr.matches(DLVRYrxStr)) {
    Log.e(TAG, "[" + DATAstr + "] doesn't match regex");
    break;
}
Matcher Dmatch = P.matcher(DATAstr);

К сожалению (?) шаблон действительно совпадает и, таким образом, попадает в строку P.matcher, строка после которой выдает исключение, когда я пытаюсь прочитать первую совпадающую группу:

W/System.err( 1238): java.lang.IllegalStateException: No successful match so far
W/System.err( 1238):    at java.util.regex.Matcher.ensureMatch(Matcher.java:607)
W/System.err( 1238):    at java.util.regex.Matcher.group(Matcher.java:358)

Решение состоит в том, чтобы добавить проверку ".matches()", как показано ниже:

Matcher Dmatch = DLVRYrx.matcher(DATAstr);
Dmatch.matches();
String data1 = Dmatch.group(0);

Да, я использую это в операторе if в своем коде, но оставить его свободно висящим, как указано выше, работает нормально.


person mikebabcock    schedule 27.03.2012    source источник
comment
myregexp.com/signedJar.html действительно полезен при создании регулярных выражений, может выделять группы, копировать из/ к синтаксису java и т. д.   -  person zapl    schedule 27.03.2012
comment
Как уже говорилось, регулярное выражение работает с образцом строки, явно заданной в коде. Это не работает только с (той же) строкой, проанализированной из файла. Кроме того, я использую тестер регулярных выражений Brosinski для Eclispe.   -  person mikebabcock    schedule 27.03.2012
comment
Обновление Android SDK (кажется, одна версия позади), на всякий случай.   -  person mikebabcock    schedule 27.03.2012


Ответы (1)


Ваш DLVRYrx.matcher(...).groupCount() просто говорит вам, что в шаблоне, из которого он был создан, есть 3 совпадающие группы.

то есть (\\d+\\s\\p{Letter}+\\s\\d+), (\\d+(?:\\.\\d+) и (\\d+)

Вам нужно позвонить либо

matcher.matches()

matcher.lookingAt()

or

matcher.find()

Прежде чем пытаться получить matcher.group(0), так как эти методы предлагают java проанализировать строку.

person Shaded    schedule 27.03.2012
comment
См. мою отредактированную версию выше; матч работает. p{L} и p{Letter} эквивалентны и используются для любой буквы в Unicode. Они также работают со спичками. - person mikebabcock; 27.03.2012
comment
Протестировано также замена всех букв «p {Letter}» на «w» ... та же ошибка. - person mikebabcock; 27.03.2012
comment
@mikebabcock Извините, я не видел этого раньше — смотрите обновления — кроме того, после того, как вы создадите свой Matcher и прежде чем вы сможете получить matcher.group(0), вам нужно запустить matcher.matches(). Попробуйте это. - person Shaded; 27.03.2012
comment
Добавление matcher.matches() устранило проблему, но поскольку количество групп возвращалось к 3, а шаблон совпадал, я бы посчитал это логической ошибкой в ​​​​библиотеке. Он должен работать без тестирования match(). - person mikebabcock; 27.03.2012
comment
Примечание: пожалуйста, сделайте репост комментария matcher.matches выше в качестве ответа, который я с радостью приму, чтобы не запутать проблему, приняв ваш более длинный ответ выше. Также обратите внимание: \p{L} отлично подходит. - person mikebabcock; 27.03.2012
comment
Ответ @mikebabcock снова обновлен. Извините за неправильные ответы, рад, что теперь это работает! - person Shaded; 27.03.2012