Le espressioni regolari ricorsive possono farlo!
Così semplice e ovvio algoritmo per rilevare una stringa che contiene un palindromo:
(\w)(?:(?R)|\w?)\1
Su rexegg.com/regex-recursion il tutorial spiega come funziona.
Funziona bene con qualsiasi linguaggio, qui un esempio adattato dalla stessa fonte (link) come proof-of-concept, 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";
}
uscite
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
Confronto
L'espressione regolare ^((\w)(?:(?1)|\w?)\2)$
fa lo stesso lavoro, ma come sì / no invece "contiene".
PS: sta usando una definizione in cui "o" non è un palimbromo, il formato con trattino "abile-elba" non è un palindromo, ma "abile" lo è. Denominarlo definizione 1 .
Quando "o" e "abile-elba" sono palindroni, denominazione definizione2 .
Confrontando con un'altra "regex palindromo",
^((.)(?:(?1)|.?)\2)$
la base-regex sopra senza \w
restrizioni, che accetta "abile-elba".
^((.)(?1)?\2|.)$
( @LilDevil ) Usa la definizione2 (accetta "o" e "abile-elba" così differenti anche nel riconoscimento delle stringhe "aaaaa" e "bbbb").
^((.)(?1)\2|.?)$
( @Markus ) non ha rilevato "kook" né "bbbb"
^((.)(?1)*\2|.?)$
( @Csaba ) Usa definizione 2 .
NOTA: per confrontare puoi aggiungere più parole $subjects
e una riga per ogni regex confrontata,
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";