Como esse padrão PCRE detecta palíndromos?
Esta pergunta é uma demonstração educacional do uso de lookahead, referência aninhada e condicionais em um padrão PCRE para corresponder a TODOS os palíndromos, incluindo aqueles que não podem ser correspondidos pelo padrão recursivo fornecido na página de manual do PCRE.
Examine este padrão PCRE no trecho de código PHP:
$palindrome = '/(?x)
^
(?:
(.) (?=
.*
(
\1
(?(2) \2 | )
)
$
)
)*
.?
\2?
$
/';
Esse padrão parece detectar palíndromos, como visto nos casos de teste (veja também em ideone.com):
$tests = array(
# palindromes
'',
'a',
'aa',
'aaa',
'aba',
'aaaa',
'abba',
'aaaaa',
'abcba',
'ababa',
# non-palindromes
'aab',
'abab',
'xyz',
);
foreach ($tests as $test) {
echo sprintf("%s '%s'\n", preg_match($palindrome, $test), $test);
}
Então, como esse padrão funciona?
NotasEsse padrão usa umreferência aninhada, que é uma técnica semelhante usada emComo esse regex Java detecta palíndromos?, mas, diferentemente do padrão Java, não há como esconder (mas ele usa umcondicional)
Observe também que o PCREpágina de manual apresenta um padrão recursivo para corresponder a alguns palíndromos:
# the recursive pattern to detect some palindromes from PCRE man page
^(?:((.)(?1)\2|)|((.)(?3)\4|.))$
A página de manual avisa que esse padrão recursivo NÃO pode detectar todos os palíndromos (consulte:Por que esse regex recursivo corresponde apenas quando um personagem repete 2n 1 vezes? etambém em ideone.com), mas o padrão de referência aninhada / padrão de aparência positiva apresentado nesta pergunta pode.