Regex - Subexpressão independente

PHPPerl
Enviado por Eclesiastes em Seg, 16/10/2006 - 21:01.PHP | Perl

(?>pattern)

É uma subexpressão "independente". Ela casa uma substring de forma autônoma se ancorada em dada posição, e somente esta substring.

Quero dizer, ^(?>a*)ab jamais irá casar, visto que (?>a*) (ancorada com o começo da string, como acima) irá casar todos caracteres a no começo da string,
não deixando nenhum a para casar ab. Em contraste, a*ab irá casar igual a a+b, já que o casamento do subgrupo a* está sendo influenciado pelo grupo seguinte ab.
Em particular, a* dentro a*ab irá casar menos caracteres que a* sozinho, já que casa até a parte final.

Um efeito similiar de (?>pattern) pode ser obtido por

    (?=(pattern))\1

visto que o lookahead está no contexto "lógico", casando a substring como a+. O retrovisor \1 guarda a string que casou, fazendo a afirmação do zero-length em analogia com (?>...).
(A diferença entre estes dois construtores é que o segundo utiliza um grupo para armazenar (catching group), modificando o número de retrovisores no resto da expressão regular.)

Este construtor é utilizado para otimizações de "eternidade" de casamentos, já que ele não irá fazer backtrack.

    m{ \(
          ( 
            [^()]+ 
          | 
            \( [^()]* \)
          )+
       \) 
     }x

Isto irá eficientemente casar um grupo não vazio com 2 ou menos níveis de parênteses. Contudo, se não há o tal grupo, ele testará virtualmente toda a string.
Isso porque há várias maneiras de dividir toda a string em diversas substrings. Isto que (.+)+ está fazendo, e (.+)+ é similar para a subexpressão da expressão acima.
Considere a expressão acima detectando que não casou em ((()aaaaaaaaaaaaaaaaaa em alguns segundos, porém para cada letra o tempo é dobrado.
Esta performace exponencial irá fazer parecer que seu programa ficou travado.

Contudo, um pequena modificação desta expressão

    m{ \( 
          ( 
            (?> [^()]+ )
          | 
            \( [^()]* \)
          )+
       \) 
     }x

usar (?>...) casa exatamente com o acima faz (verifique você mesmo, seria um exercício produtivo),
mas termina em um quarto do tempo quando usado numa string similar como 1000000 letras "a" ("aaaaa...a").
Fique ciente, contudo, que esta expressão atualmente dispara um aviso sob -w dizendo o seguinte: "matches the null string many times"):

Num grupo simples, com tal expressão (?> [^()]+ ), um efeito comparavél pode ser obtido com negative lookahead, dessa forma [^()]+ (?! [^()] ). Esta faria 4 vezes mais lenta em uma string com 1000000 letras "a".

Créditos