Ошибка регулярного выражения Java - поиск назад со ссылкой на группу

Я пытаюсь создать регулярное выражение, которое соответствует ровно двум экземплярам символа в классе. Это регулярное выражение, которое я сделал:

(?<!\1)([^raol1c])\1(?!\1)

Как видите, здесь используются негативы в упреждающем и обратном направлении. Но, как обычно, последнее не работает; java выдает хорошо известное исключение «группа просмотра не имеет очевидной максимальной длины», когда она явно имеет максимальную длину (ровно один символ).

В идеале регулярное выражение должно соответствовать «hh», «jhh», «ahh», «hhj», «hha», но не «hhh».

Есть идеи о том, как с этим справиться и найти обходной путь?


person user2402372    schedule 20.05.2013    source источник
comment
Есть ли установленная длина проверяемых строк?   -  person Andrew Clark    schedule 20.05.2013
comment
Нет, струны могут быть любой длины.   -  person user2402372    schedule 20.05.2013
comment
Я не понимаю вашего правила: должно "hhaa" совпадать?   -  person jlordo    schedule 20.05.2013
comment
да. Поскольку регулярное выражение соответствует hh, тогда ожидает отрицательного совпадения h и ищет отрицательное совпадение h, что верно в обоих случаях.   -  person user2402372    schedule 20.05.2013
comment
Для действительно простого обходного пути, выходящего за рамки одного регулярного выражения, найдите ([^raol1c])\1+ и убедитесь, что результат не превышает двух символов.   -  person Martin Ender    schedule 20.05.2013
comment
возможный дубликат обратных ссылок в ретроспективе   -  person Martin Ender    schedule 20.05.2013
comment
Обратите внимание, что даже если бы обратные ссылки можно было напрямую использовать внутри ретроспективного просмотра, это регулярное выражение не будет работать, потому что в то время, когда (?<!\1) будет оцениваться, \1 еще не захвачен. Это должен быть ([^raol1c])(?<!\1.)\1(?!\1), который работает в PCRE2.   -  person Deadcode    schedule 07.12.2019


Ответы (1)


Вот обходной путь. Это некрасиво, но, видимо, работает:

(?<!(?=\1).)([^raol1c])\1(?!\1)

Помещение обратной ссылки в предварительный просмотр нулевой длины внутри ретроспективного просмотра делает ретроспективный просмотр определенно фиксированной длины.

Отказ от ответственности, я не придумал этого (к сожалению): Обратные ссылки в ретроспективе

РЕДАКТИРОВАТЬ:

Приведенный выше образец по какой-то причине не исключает hhh. Однако это работает:

(?<!(.)(?=\1))([^raol1c])\2(?!\2)

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

Рабочая демонстрация.

person Martin Ender    schedule 20.05.2013
comment
Неплохо. Для использования с Matcher.matches (). - person Mena; 20.05.2013
comment
Код Pattern.compile("(?<!(?=\\1).)([^raol1c])\\1(?!\\1)").matcher("hhh").find() возвращает true, но должен быть false. Он также возвращает true с hh. - person user2402372; 20.05.2013
comment
@ user2402372 У меня рабочая версия. Редактировать через секунду. - person Martin Ender; 20.05.2013
comment
Это может быть выполнено одним символом: ([^raol1c])(?<!(?=\1)..)\1(?!\1) - person Deadcode; 07.12.2019