Expressions régulières en C

Gazette Linux n°55 — Juillet 2000

Fabien Niñoles

Adaptation française 

Frédéric Marchal

Correction du DocBook 

Article paru dans le n°55 de la Gazette Linux de juillet 2000.

Cet article est publié selon les termes de la Open Publication License. La Linux Gazette n'est ni produite, ni sponsorisée, ni avalisée par notre hébergeur principal, SSC, Inc.


Table des matières

Introduction
La Bibliothèque GNU C et les expressions régulières
Mygrep.c

Introduction

Dans cette série d'articles, j'ai l'intention d'explorer les implémentations variées des chaînes de caractères dans les langages communs à la plate-forme Linux. Le premier article explorera la bibliothèques d'expressions régulières fournit avec GNU libc. Dans les articles suivants, j'espère voir les autres librairies usuelles et les langages — les fonctions de trie par total factice (hash functions) en Java et les chaînes dans KDE versus les chaînes dans Gnome.

Chaque langage a ses forces et ses faiblesses. J'espère qu'en faisant une partie du travail à votre place, je serai capable de vous donner un bref aperçu des capacités et faiblesses des langages les plus communs et de leurs bibliothèques en regard à la manipulation de chaînes de caractères.

Je ne parlerai ni d'internationalisation ni de localisation dans cette série d'articles, puisque ces sujets méritent des volumes complets d'études et non pas un court sommaire.

La Bibliothèque GNU C et les expressions régulières

La bibliothèque GNU C est l'élément de base de toute installation Linux du point de vue du programmeur. La plupart des bibliothèques de niveau plus élevé sont basées sur libc, et la plupart des éléments que l'on considère comme faisant partie du langage C sont vraiment des fonctions de libc.

Les chaînes de caractères en C sont juste des vecteurs de caractères, possiblement étendus, terminés par un caractère nul. C'est la plus simple et la plus efficace des implémentations de chaînes en termes de ressources de calcul, mais c'est aussi probablement la plus compliquée et la moins efficace des implémentations pour le programmeur. Puisque les chaînes sont soit des constantes (ie. des valeurs littérales) soit des pointeurs, le programmeur à la capacité de manipuler les chaînes jusqu'au niveau des bits et à toute sorte d'opportunités pour optimiser son code (par exemple ce bout de code). D'un autre coté, la terminaison nulle des chaînes et l'absence de vérification intégrée de la longueur annonce des problèmes tels que des boucles infinies et des débordements de tampons vont apparaître inévitablement dans le code.

La bibliothèque GNU C est riche en fonctions pour la manipulation de chaînes. Il y a les appels standards pour la copie, le déplacement, la concaténation, la comparaison et pour trouver la longueur d'une chaîne (ou d'une région de mémoire). En plus de cela, libc supporte aussi le marquage (tokenization) la recherche d'expressions régulières.

Les expressions régulières sont une méthode puissante pour rechercher un texte auquel correspond un motif particulier. La plupart des usagers ont rencontré l'idée des expressions régulières pour la première fois sur la ligne de commande, où des caractères comme l'astérisque ont une signification particulière (dans ce cas-ci, remplace aucun ou plusieurs caractères). Pour démontrer la puissance des expressions régulières et comment les utiliser, nous implémenterons une forme simplifier de grep.

Mygrep.c utilise la puissante bibliothèque regex.h pour faire sa recherche à travers un fichier texte afin de trouver une ligne qui correspond au motif donné.

bash> ./mygrep -f mygrep.c -p int
Line 17: int match_patterns(regex_t *r, FILE *FH)
Line 36: printf("Line %d:%s", line_no, line);
Line 52: printf("In error\n");
bash>

Libc rend l'utilisation des expressions régulières relativement aisé. Bien sûr, il serait plus facile d'utiliser un langage qui supporterait directement les expressions régulières (comme perl) pour cet exemple, mais la bibliothèque C a l'avantage d'une intégration facile au code existant et probablement d'un gain en vitesse (bien que dans les langages comme perl, les expressions régulières sont fortement optimisées).

Si vous examinez le code du programme, vous verrez que mygrep.c consiste principalement d'une fonction principale qui manipule les options de l'usager et de deux fonctions qui font le travail d'appariement de l'expression régulière. La première de ces fonctions, logiquement, est do_regex(). Cette fonction prend comme paramètres un pointeur sur une structure d'expression régulière, une chaîne contenant le motif à rechercher et une chaîne contenant le nom du fichier. La première tâche de do_regex() est de « compiler » l'expression régulière dans un format natif à la bibliothèque GNU en appelant regcomp(). Ce format est une structure de données optimisé pour l'appariement de motif, les détails de ce dernier était caché à l'usager. Ensuite, le fichier a balayé est ouvert, puis l'identificateur de fichier et l'expression régulière compilée sont passée à match_patterns() pour l'exécution de la recherche et la sortie des résultats.

match_patterns() balaie à travers chaque ligne du fichier, recherchant des motifs qui s'apparieraient à l'expression régulière. On commence par balayer les lignes une à une — remarquez que nous assumons que chaque ligne fait moins de 1023 octets (le vecteur appelé line fait 1024 octets et on a besoin d'un caractère pour la terminaison nulle). Si la ligne fait plus de 1023 octets, alors la ligne est coupée et le reste interprété comme une nouvelle ligne jusqu'à ce que le caractère '\n' soit rencontré. La fonction regexec() balaie la ligne pour un ensemble de caractères qui correspondent au motif spécifié par l'usager. Chaque ensemble de caractères qui correspond à l'expression régulière force regexec() à retourner 0, provoquant l'impression de la ligne ainsi que son numéro. Si l'expression régulière s'apparient plus d'une fois sur la même ligne, la ligne est imprimée autant de fois. Le décalage du début de la ligne est mis à jour de sorte que le motif correspondant n'est pas le même à chaque fois.

Cet exemple, bien que très simple, démontre à quel point la bibliothèque GNU C peut être puissante. Quelques-unes de des capacités les plus remarquables de la bibliothèque que nous avons utilisé inclut :

  • La capacité de manipuler auto-magiquement des lignes extrêmement longues.

  • Des structures de données optimisées pour des fonctions particulières.

  • Un mécanisme standard et portable pour la manipulation d'erreurs.

  • Un mécanisme standard et portable pour lire les options de la ligne de commande.

En particulier, nous avons exploré la puissante bibliothèque d'expression régulière GNU regex.h, qui simplifie l'inclusion des expressions régulières dans vos programmes, et fournit une interface simple et sécuritaire à ces capacités.

Adaptation française de la Gazette Linux

L'adaptation française de ce document a été réalisée dans le cadre du Projet de traduction de la Gazette Linux.

Vous pourrez lire d'autres articles traduits et en apprendre plus sur ce projet en visitant notre site : http://www.traduc.org/Gazette_Linux.

Si vous souhaitez apporter votre contribution, n'hésitez pas à nous rejoindre, nous serons heureux de vous accueillir.