Rekurencyjne wyrażenia regularne mogą to zrobić!
Tak prosty i oczywisty algorytm do wykrywania łańcucha zawierającego palindrom:
(\w)(?:(?R)|\w?)\1
Na rexegg.com/regex-recursion samouczek wyjaśnia, jak to działa.
Działa dobrze z każdym językiem, tutaj przykład zaadaptowany z tego samego źródła (linku) co dowód słuszności koncepcji, używając 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";
}
wyjścia
dont
o
oo
kook
book
paper
kayak
okonoko
aaaaa
bbbb
Porównywanie
Wyrażenie regularne ^((\w)(?:(?1)|\w?)\2)$
wykonuje to samo zadanie, ale zamiast tego „zawiera” tak / nie.
PS: używa definicji, w której „o” nie jest palimbromem, format łączony „w stanie elba” nie jest palindromem, ale „w stanieelba” nim jest. Nazywanie tego definicja 1 .
Kiedy „o” i „zdolna-elba” są palindronami, definicja nazewnictwa2 .
W porównaniu z innymi „wyrażeniami regularnymi palindromu”,
^((.)(?:(?1)|.?)\2)$
base-regex powyżej bez \w
ograniczeń, akceptując "ble-elba ".
^((.)(?1)?\2|.)$
( @LilDevil ) Użyj definicji2 (akceptuje "o" i "zdolny-elba", więc różni się także rozpoznawaniem ciągów "aaaaa" i "bbbb").
^((.)(?1)\2|.?)$
( @Markus ) nie wykryto „kook” ani „bbbb”
^((.)(?1)*\2|.?)$
( @Csaba ) Użyj definicji2 .
UWAGA: aby porównać, możesz dodać więcej słów w $subjects
i wiersz dla każdego porównywanego wyrażenia regularnego,
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";