110 votes

Comment vérifier qu'une chaîne de caractères est un palindrome à l'aide d'expressions régulières ?

C'était une question d'entretien à laquelle je n'ai pas pu répondre :

Comment vérifier qu'une chaîne de caractères est un palindrome à l'aide d'expressions régulières ?

p.s. Il y a déjà une question " Comment vérifier si la chaîne de caractères donnée est palindrome ? "et cela donne beaucoup de réponses dans différentes langues, mais aucune réponse qui utilise des expressions régulières.

1 votes

stackoverflow.com/questions/3644266/ peut donner une idée.

3 votes

De nos jours (2018) et pour ceux qui recherchent "la regex palindrome", voir la discussion sur le support PCRE motifs récursifs au lien de Prakhar, et mon regex récursif ci-dessous, avec des comparaisons .

183voto

Jose M Vidal Points 3456

La réponse à cette question est "c'est impossible". Plus précisément, l'enquêteur se demande si vous avez été attentif dans votre cours de théorie computationnelle.

Dans votre cours de théorie informatique, vous avez appris les machines à états finis. Une machine à états finis est composée de nœuds et d'arêtes. Chaque arête est annotée d'une lettre d'un alphabet fini. Un ou plusieurs nœuds sont des nœuds spéciaux "acceptants" et un nœud est le nœud "de départ". Au fur et à mesure que chaque lettre est lue dans un mot donné, nous traversons l'arête donnée dans la machine. Si nous arrivons dans un état d'acceptation, nous disons que la machine "accepte" ce mot.

Une expression régulière peut toujours être traduite en une machine à états finis équivalente. C'est-à-dire une machine qui accepte et rejette les mêmes mots que l'expression régulière (dans le monde réel, certains langages regexp autorisent des fonctions arbitraires, mais celles-ci ne comptent pas).

Il est impossible de construire une machine à états finis qui accepte tous les palindromes. La preuve repose sur le fait que nous pouvons facilement construire une chaîne qui nécessite un nombre arbitrairement grand de nœuds, à savoir la chaîne

a^x b a^x (par exemple, aba, aabaa, aaabaaa, aaaabaaaa, ....)

où a^x est a répété x fois. Cela nécessite au moins x nœuds car, après avoir vu le "b", nous devons compter x fois en arrière pour nous assurer qu'il s'agit bien d'un palindrome.

Enfin, pour en revenir à la question initiale, vous pourriez dire à votre interlocuteur que vous pouvez écrire une expression régulière qui accepte tous les palindromes dont la taille est inférieure à une longueur fixe finie. S'il existe un jour une application du monde réel nécessitant l'identification de palindromes, il est presque certain qu'elle n'inclura pas les palindromes de longueur arbitraire. Cette réponse montrerait donc que vous pouvez faire la différence entre les impossibilités théoriques et les applications du monde réel. Néanmoins, la regexp réelle serait assez longue, bien plus longue que le programme équivalent de 4 lignes (exercice facile pour le lecteur : écrire un programme qui identifie les palindromes).

13 votes

@SteveMoser Dans Ruby 1.9.x, les expressions régulières ne sont plus régulières (au sens de la théorie des automates) et donc des choses comme la vérification des palindromes sont possibles. Cependant, à toutes fins utiles, les palindromes ne peuvent pas être vérifiés avec une expression régulière. Régulier regex (ça a du sens ?).

1 votes

@SteveMoser Il existe une bonne description du moteur d'expressions régulières de Ruby ( >=1.9 ) aquí

0 votes

@John right, donc dans le contexte de la question Jose a raison et hqt a tort.

47voto

Airsource Ltd Points 14291

Alors que le PCRE prend en charge les expressions régulières récursives (voir la réponse de Peter Krauss ), vous ne pouvez pas utiliser une regex sur l'option UNITÉ DE SOINS INTENSIFS (comme celui utilisé, par exemple, par Apple) pour y parvenir sans code supplémentaire. Vous devrez faire quelque chose comme ceci :

Cela détecte tout palindrome, mais nécessite une boucle (qui sera nécessaire car les expressions régulières ne peuvent pas compter).

$a = "teststring";
while(length $a > 1)
{
   $a =~ /(.)(.*)(.)/;
   die "Not a palindrome: $a" unless $1 eq $3;
   $a = $2;
}
print "Palindrome";

6 votes

Bonne réponse. La question ne demandait pas une seule regexp qui détecte un palindrome immédiatement - elle demandait simplement une méthode de détection des palindromes qui utilise des regexps. Félicitations pour la perspicacité avec laquelle vous avez envisagé la question.

1 votes

Voir aussi la correspondance la plus simple (sans manipulation de chaîne) utilisant une seule regex, stackoverflow.com/a/48608623/287948

0 votes

Merci @PeterKrauss. Je ne savais pas que le PCRE avait une récursion. Je me suis référé à votre réponse.

37voto

ZCHudson Points 366

Ce n'est pas possible. Les palindromes ne sont pas définis par un langage régulier. (Vous voyez, j'ai vraiment appris quelque chose en théorie informatique)

2 votes

La plupart des moteurs d'expressions régulières capturent plus que les langages réguliers (net peut capturer les parenthèses correspondantes par exemple). Seules les regex standard sont limitées aux langages réguliers.

0 votes

La question utilisait le terme "expression régulière" cependant... donc la réponse de ZCHudson est correcte.

2 votes

@austirg : La réponse de ZCHudson est correcte mais incomplète. Les expressions régulières utilisées dans les langages de programmation modernes et les expressions régulières utilisées dans les cours théoriques de CS sont des bêtes différentes. Le terme est juste un héritage historique. Voir stackoverflow.com/questions/233243#235199 et ma réponse.

32voto

Markus Jarderot Points 33893

Avec Perl regex :

/^((.)(?1)\2|.?)$/

Cependant, comme beaucoup l'ont fait remarquer, cela ne peut pas être considéré comme une expression régulière si l'on veut être strict. Expressions régulières ne supporte pas la récursion.

0 votes

Cela ne fonctionne pas en PCRE (il ne correspond pas à "ababa"), mais cela fonctionne en Perl 5.10

0 votes

Vous avez raison. PCRE semble traiter la récursion comme un groupe atomique, alors que Perl autorise le retour en arrière à l'intérieur de celui-ci. Je ne pense pas qu'il soit possible de faire cette vérification en PCRE.

1 votes

Étonnamment, cela ne fonctionne pas pour les langues non latines, par exemple la langue arménienne.

18voto

FOR Points 1747

Voici un pour détecter les palindromes de 4 lettres (ex : deed), pour tout type de caractère :

\(.\)\(.\)\2\1

Voici un pour détecter les palindromes à 5 lettres (ex : radar), en vérifiant uniquement les lettres :

\([a-z]\)\([a-z]\)[a-z]\2\1

Il semble donc que nous ayons besoin d'une regex différente pour chaque longueur de mot possible. Ce poste sur une liste de diffusion Python comprend quelques détails sur le pourquoi (Finite State Automata and pumping lemma).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X