Expressões regulares recursivas podem fazer isso!
Algoritmo tão simples e evidente para detectar uma string que contém um palíndromo:
(\w)(?:(?R)|\w?)\1
Em rexegg.com/regex-recursion, o tutorial explica como funciona.
Funciona bem com qualquer linguagem, aqui um exemplo adaptado da mesma fonte (link) como prova de conceito, usando PHP:
$subjects=['dont','o','oo','kook','book','paper','kayak','okonoko','aaaaa','bbbb'];
$pattern='/(\w)(?:(?R)|\w?)\1/';
foreach ($subjects as $sub) {
echo $sub." ".str_repeat('-',15-strlen($sub))."-> ";
if (preg_match($pattern,$sub,$m))
echo $m[0].(($m[0]==$sub)? "! a palindrome!\n": "\n");
else
echo "sorry, no match\n";
}
saídas
dont ------------> sorry, no match
o ---------------> sorry, no match
oo --------------> oo! a palindrome!
kook ------------> kook! a palindrome!
book ------------> oo
paper -----------> pap
kayak -----------> kayak! a palindrome!
okonoko ---------> okonoko! a palindrome!
aaaaa -----------> aaaaa! a palindrome!
bbbb ------------> bbb
Comparando
A expressão regular ^((\w)(?:(?1)|\w?)\2)$
faz o mesmo trabalho, mas sim / não em vez de "contém".
PS: está usando uma definição onde "o" não é um palimbrome, o formato hifenizado "able-elba" não é um palíndromo, mas "ableelba" é. Nomeando-o como definição1 .
Quando "o" e "able-elba" são palíndrons, nomeando a definição 2 .
Comparando com outros "regexes de palíndromo",
^((.)(?:(?1)|.?)\2)$
a base-regex acima sem \w
restrição, aceitando "able-elba".
^((.)(?1)?\2|.)$
( @LilDevil ) Use a definição2 (aceita "o" e "able-elba", diferindo também no reconhecimento das strings "aaaaa" e "bbbb").
^((.)(?1)\2|.?)$
( @Markus ) não detectou "kook" nem "bbbb"
^((.)(?1)*\2|.?)$
( @Csaba ) Use a definição2 .
NOTA: para comparar, você pode adicionar mais palavras em $subjects
e uma linha para cada regex comparada,
if (preg_match('/^((.)(?:(?1)|.?)\2)$/',$sub)) echo " ...reg_base($sub)!\n";
if (preg_match('/^((.)(?1)?\2|.)$/',$sub)) echo " ...reg2($sub)!\n";
if (preg_match('/^((.)(?1)\2|.?)$/',$sub)) echo " ...reg3($sub)!\n";
if (preg_match('/^((.)(?1)*\2|.?)$/',$sub)) echo " ...reg4($sub)!\n";