Para encontrar todos os¹ os palíndromos de 3 ou mais caracteres que não estão dentro de [...] :
$ echo 'cac[ada]abacab' | perl -nle '
while (/\[.*?\]|(?=(([^][])(?1)|[^][]?))./g) {
print $1 if length $1 >= 3
}'
cac
aba
bacab
aca
(observe que ele assume caracteres de byte único, adicione -Mopen=locale para a definição de caracteres do idioma).
O núcleo da correspondência do palíndromo é uma expressão regular recursiva. Um palíndromo é correspondido como uma string vazia ou um único caractere ou um par de caracteres correspondentes com outro palíndromo entre eles. Isso seria ((.)(?1)|.?) , onde (?1) faz a parte recursiva (corresponde ao que está dentro da primeira parte de () , exceto que aqui substituímos . por [^][] (qualquer caractere diferente de ] e [ ).
Ao corresponder todas ocorrências com /.../g , o perl pesquisa a próxima ocorrência após o final da primeira, portanto, se tivéssemos \[.*?\]|(([^][])(?1)|[^][]?) , não encontraríamos bacab in abacab porque primeiro encontraria aba e, em seguida, retomaria a pesquisa após esse aba . Então, aqui, em vez disso, combinamos (?=(palindrome)). , que corresponde a um único caractere ( . ), desde que ele esteja no início de um palíndromo , que é então capturado em $1 . Isso significa que retomaremos a pesquisa após esse único caractere.
¹ Estritamente falando, ele encontra os palíndromes mais longos (com 3 caracteres ou mais) em todas as posições da string, ignorando o [...] s, portanto, ele pode não encontrar todos os ocorrências. Por exemplo, em ababa , encontraria ababa na primeira posição, bab na terceira posição, aba na segunda posição, mas não aba na primeira posição.