Vérification du parenthésage⚓︎
Avec seulement un type de parenthèses⚓︎
Vérification du parenthésage
La vérification du parenthésage est une étape importante lors de l'analyse d'une expression mathématique ou même lors de l'interprétation/compilation d'un programme informatique.
Pour simplifier, nous ne considérerons que des expressions formées uniquement de parenthèses ouvrantes et fermantes, mais cela ne change rien si on rajoute des opérations mathématiques ou des instructions informatiques entre parenthèses. Ainsi, '(4+5)*(7-1)'
ou '(A or B) and (A or C)'
seront simplifiées en '()()'
.
Pour l'instant nous allons aussi supposer que les expressions sont uniquement composées de '('
et ')'
.
Pour qu'une expression parenthésée soit valide, il faut que toute parenthèse ouvrante soit suivie d'une parenthèse fermante et que toute parenthèse fermante soit précédée d'une parenthèse ouvrante.
Par exemple, '(())'
et '(()())'
sont valides mais pas '(()'
, '(()))'
ou encore ')('
.
Un algorithme pour vérifier le parenthésage des expressions
Le moyen le plus simple pour vérifier si les parenthèses dans une expression sont valides, il suffit de compter combien de parenthèses sont ouvertes. À chaque fois qu'on voit une parenthèse ouvrante, on augmente de 1 le compteur et on le diminue de 1 à chaque fois qu'on voit une parenthèse fermante.
À la fin, il faut que le compteur soit égal à 0. Il faut également qu'à chaque instant il soit positif ou nul. S'il est négatif, l'expression n'est pas valide.
Exercice 2
Écrire le code de la fonction verif_parentheses
qui prend en paramètre une chaîne de caractères expression
et qui renvoie un booléen indiquant si l'expression est bien parenthésée ou non.
>>> verif_parentheses('(())')
True
>>> verif_parentheses('(()())')
True
>>> verif_parentheses('(()')
False
>>> verif_parentheses('(()))')
False
>>> verif_parentheses(')(')
False
Indication
Pour le return
final, on pourrait utiliser un if
afin de déterminer s'il faut renvoyer True
ou False
. Mais dans ce cas, il vaut mieux renvoyer directement le résultat du test effectué.
Ainsi, au lieu d'écrire :
if TEST:
return True
else:
return False
on peut écrire :
return TEST
# Tests
(insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Le problème du parenthésage et les automates d'états finis
Le problème de vérification de parenthésage est un problème classique en informatique.
Même s'il a l'air simple, il est impossible de résoudre ce problème sans mémoire. En effet, il faut pouvoir compter le nombre de parenthèses ouvrantes pour savoir s'il y a autant de parenthèses fermantes.
Beaucoup de problèmes concernant les textes peuvent être résolus avec des systèmes sans mémoire comme les expressions régulières ou les automates finis d'états.
Chercher un mot dans un texte est un problème qui peut être résolu par ces systèmes.
Autre exemple, ces deux systèmes peuvent déterminer si un texte est une adresse mail valide. En simplifiant grossièrement, on peut résumer cette vérification en 4 états :
- On n'a pas encore vu de
@
. - On a vu
@
mais pas encore de.
. - On a vu
@
et on vient de voir un.
. - On a vu
@
et au moins un caractère depuis le dernier.
.
En plus de ces états on peut rajouter un état d'erreur dans lequel on arrive si on voit un caractère interdit ou un deuxième @
.
On peut simplifier le problème du parenthésages à des expressions de la forme ((()))
. Il suffit de s'assurer qu'on ferme autant de parenthèses qu'on en a ouvertes. On a donc besoin des états :
- Il y a 0 parenthèse ouverte.
- Il y a 1 parenthèse ouverte.
- Il y a 2 parenthèses ouvertes.
- ...
On voit bien qu'il va falloir un nombre infini d'états pour traiter ce problème dans le cas général. Or, comme leur nom l'indique, les automates d'états finis ont un nombre fini d'états. Pour les parenthèses, le seul moyen de garder un nombre fini d'états ou d'instructions, c'est d'avoir une variable pour compter les parenthèses ouvrantes.
Pour en découvrir davantage les expressions régulières et les automates d'états finis, vous pouvez aller faire cet exercices sur CodEx
Avec plusieurs types de parenthèses⚓︎
Les compteurs ne sont pas suffisants
Si on veut traiter des expressions où on mélange plusieurs types de parenthèses, comme '()'
et '[]'
, il ne suffit plus de compter. en effet, même si on a un compteur par type de parenthèses, il faut pouvoir rejeter '([)]
. Il faut donc se rappeler de l'ordre dans lequel on a vu chaque parenthèse ouvrante.
C'est pourquoi on utilise une pile. L'algorithme est alors :
- Lorsqu'on voit une parenthèse ouvrante, on la met au sommet de la pile.
- Lorsqu'on voit une parenthèse fermante, on dépile la dernière parenthèse ouvrante non encore fermée et on vérifie que c'est bien le même type de parenthèse.
- À la fin, la pile doit être vide.
L'interface pour les piles
Pour l'exercice suivant, vous pouvez utiliser les fonctions cree_pile
, empile
, depile
et est_vide
. L'implémentation n'est pas donnée et ne correspond pas à celle de l'exercice 1. Vous ne pouvez donc utiliser que ces fonctions pour manipuler la pile. Vous pouvez utiliser help(LA_FONCTION)
pour avoir plus d'information.
Exercice 3
Écrire le code de la fonction verif_parentheses2
qui prend en paramètre une chaîne de caractères expression
et qui renvoie un booléen indiquant si le parenthésage de cette expression est valide. Les parenthèses possibles sont '()'
et '[]'
.
On pourra utiliser le dictionnaire parentheses_ouvrantes
qui associe chaque parenthèse ouvrante à une parenthèse fermante. On pourra également utiliser la liste parenthess_fermantes
qui contient toutes les parenthèses fermantes possibles.
>>> verif_parentheses2('()[]{}')
True
>>> verif_parentheses2('([{}])')
True
>>> verif_parentheses2('(([({}[])]{()})[])')
True
>>> verif_parentheses2('([)]')
False
>>> verif_parentheses2('(}')
False
>>> verif_parentheses2('())(')
False
Indications
Indication 1
Pour savoir si un symbole est une parenthèse ouvrante, il suffit de regarder s'il est dans parentheses_ouvrantes
.
Indication 2
Avant de dépiler, il faut s'assurer que la pile n'est pas vide. Et si elle est vide, c'est que l'expression n'est pas valide.
Indication 3
Pour savoir si une parenthèse fermante correspond à une parenthèse ouvrante, il faut regarder quel symbole est associé à la parenthèse ouvrante dans parentheses_ouvrantes
.
Indication 4
À la fin de l'expression, pour déterminer si elle est valide, il suffit de regarder si la pile est vide.
# Tests
(insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
# Tests
(insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
# Tests
(insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)