Обратные ссылки в ретроспективе

Можете ли вы использовать обратные ссылки в ретроспективе?

Допустим, я хочу split везде, где позади меня, символ повторяется дважды.

    String REGEX1 = "(?<=(.)\\1)"; // DOESN'T WORK!
    String REGEX2 = "(?<=(?=(.)\\1)..)"; // WORKS!

    System.out.println(java.util.Arrays.toString(
        "Bazooka killed the poor aardvark (yummy!)"
        .split(REGEX2)
    )); // prints "[Bazoo, ka kill, ed the poo, r aa, rdvark (yumm, y!)]"

Использование REGEX2 (где обратная ссылка находится в предварительном просмотре, вложенном в предварительный просмотр назад) работает, но REGEX1 дает эту ошибку во время выполнения:

Look-behind group does not have an obvious maximum length near index 8
(?<=(.)\1)
        ^

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

Так есть ли способ использовать обратную ссылку в ретроспективе?

А если нет, всегда ли можно обойти это, используя этот вложенный просмотр вперед? Есть ли другие часто используемые техники?


person polygenelubricants    schedule 29.04.2010    source источник
comment
Интересно, и +1 за ваш гениальный обходной путь. Я не использую Java, поэтому сам не могу попробовать - что произойдет, если группа, на которую сделана обратная ссылка, находится за пределами обзора, например (?<=\\1)(.)?   -  person Tim Pietzcker    schedule 29.04.2010
comment
@Tim: это приводит к тому же PatternSyntaxException. Кстати, если кто-то хочет поиграть с вариантом этой проблемы, я просто написал его на codingBat: codingbat. com / prob / p266235   -  person polygenelubricants    schedule 29.04.2010
comment
@polygenelubricants Я хотел бы проголосовать за это регулярное выражение: (? ‹= (? = (.) \\ 1) ..) хотя бы 10 раз. очень элегантно!   -  person Eugene    schedule 14.08.2012


Ответы (1)


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

Я был заинтригован, узнав, что Python делает с этим регулярным выражением. Python поддерживает только ретроспективный просмотр фиксированной длины, а не конечной длины, как Java, но это регулярное выражение имеет фиксированную длину. Я не мог использовать re.split() напрямую, потому что re.split() Python никогда не разделяется при пустом совпадении, но я думаю, что нашел ошибку в re.sub():

>>> r=re.compile("(?<=(.)\\1)")
>>> a=re.sub(r,"|", "Bazooka killed the poor aardvark (yummy!)")
>>> a
'Bazo|oka kil|led the po|or a|ardvark (yum|my!)'

Поиск назад соответствует между двумя повторяющимися символами!

person Tim Pietzcker    schedule 29.04.2010
comment
Подробнее см. stackoverflow.com/questions/2628534/ регулярное выражение весело. - person polygenelubricants; 29.04.2010
comment
Это глупо, что re.split() не разбивается на пустое совпадение. Какого черта они так делают? Я думаю, что есть много раз, когда вы хотите разделить просто на основе утверждений, а не на фактическом непустом разделителе. - person polygenelubricants; 29.04.2010
comment
Я спрашивал то же самое в системе отслеживания ошибок Python. Вероятно, это было непреднамеренно, но осталось в покое, чтобы не вызвать проблем с совместимостью; сейчас ведется капитальный ремонт движка регулярных выражений, но может пройти некоторое время, пока новый модуль регулярных выражений не будет объединен со стандартной библиотекой. - person Tim Pietzcker; 29.04.2010
comment
Пакет регулярных выражений Java изначально содержал ту же ошибку, при которой ретроспективы не были привязаны к текущей позиции совпадения, но она была исправлена ​​в JDK 1.6. - person Alan Moore; 29.04.2010