Expressions régulières : le moyen simple de décrire des séquences de caractères

Depuis toujours en informatique, la recherche de caractères donnés ou de séquences de caractères concrètes dans des documents fait partie des tâches standard dont il faut régulièrement s’acquitter. L’objectif dans ce cas est souvent de modifier ou de remplacer des portions de texte ou des lignes de code. Cette tâche est d’autant plus complexe que la séquence de caractères recherchée apparaît plusieurs fois dans le document. Dans les années 1950 déjà, les experts avaient trouvé dans les langages formels de l’informatique théorique une solution qui marque aujourd’hui encore le développement de logiciels et simplifie largement ce type de tâches répétitives sous la forme d’expressions régulières (angl. regular expressions).

Qu’est-ce qu’une expression régulière ?

Les expressions régulières (angl. regular expressions) sont les unités de description de langages rationnels faisant partie des langages formels. Elles sont un instrument central de l’informatique théorique, qui forme notamment la base du développement et de l’exécution des programmes informatiques ainsi que de la construction des compilateurs requis à cet effet. C’est la raison pour laquelle les expressions régulières (souvent également qualifiées de regex et reposant sur des règles syntaxiques clairement définies) sont notamment utilisées dans le développement de logiciels.

Il existe pour chaque expression régulière un automate fini (également qualifié d’automate avec un nombre fini d’états) qui accepte un langage spécifié par l’expression et qui est développé à l’aide de la https://smart--grid.net/cours-lessons-theory/theorie-des-langages/construction-de-thompson/ - external-link-window "Présentation su concept sur smart-grid.net">construction de Thompson à partir d’une expression régulière. Il existe qui plus est pour chaque automate fini une expression régulière qui décrit le langage accepté par l’automate. Celle-ci peut être créée soit par l’algorithme de Kleene soit par l’https://fr.wikipedia.org/wiki/%C3%89limination_de_Gauss-Jordan - external-link-window "Article Wikipédia sur l’« élimination d’états de Gauss »">élimination d’états.

Note

Un automate est un modèle comportemental se composant d’états, de transitions d’état et d’actions. Il est qualifié de fini lorsque la quantité d’états qu’il peut accepter est finie (autrement dit limitée).

Un exemple connu de l’utilisation des expressions régulières en informatique est la fonction Rechercher/remplacer des éditeurs de texte que le pionnier en informatique Ken Thompson l’un des développeurs du système d’exploitation UNIX a mis en place pour la première fois dans les années 1960 dans l’éditeur orienté ligne QED, puis dans son successeur ed. Cette fonction permet de rechercher des séquences de caractères données dans des textes et de les remplacer éventuellement par une autre séquence de caractères quelconque.

Définition : Expressions Régulières

Les expressions régulières (de l’anglais regular expressions) sont des chaînes de caractères sur la base de règles syntaxiques permettant de décrire des séquences de caractères. Elles font de fait partie des langages rationnels – un sous-groupe des langages formels d’une grande importance notamment en informatique, et plus spécifiquement dans le développement de logiciels.

Comment une expression régulière fonctionne-t-elle ?

Une expression régulière peut être composée soit exclusivement de caractères normaux (par exemple abc) soit d’une combinaison de caractères normaux et de métacaractères (par exemple ab*c). Le but des métacaractères ici est de décrire des constructions ou agencements de caractères donnés, par exemple de décrire si un caractère doit se trouver au début de la ligne, s’il doit ou peut n’apparaître qu’une seule fois ou plus ou moins souvent. Les deux exemples d’expressions régulières cités fonctionnent ainsi de la manière suivante :

abc : le modèle simple de regex abc requiert une correspondance exacte. La recherche s’attachera donc à détecter des chaînes de caractères contenant non seulement tous les caractères « abc », mais les faisant également apparaître dans cet ordre précis. La correspondance demandée par l’expression se retrouve donc dans la question « Connais-tu l’abc ? » comme dans la phrase « Je dois encore soigner mon abcès ».

ab*c : des expressions régulières avec des caractères spéciaux fonctionnent en revanche un peu différemment, car la recherche se fait non seulement au niveau de correspondances exactes, mais aussi de scénarios spéciaux. L’étoile (également appelée « astérisque ») dans ce cas veille à recherche de chaînes de caractères commençant par la lettre « a » et finissant par la lettre « c », mais pouvant avoir entre les deux un nombre quelconque de lettres « b ». Il y aura donc une correspondance non seulement dans « abc », mais aussi dans les chaînes de caractères « abbbbc » et « cbbabbcba ».

Pour afficher cette vidéo, des cookies de tiers sont nécessaires. Vous pouvez consulter et modifier vos paramètres de cookies ici.

Chaque regex peut par ailleurs être reliée à une action concrète, comme la fonction « Remplacer » déjà citée. Cette action est réalisée partout où l’expression régulière correspondante apparaît, c’est-à-dire partout où il y a une correspondance exacte, comme dans les exemples présentés.

Quels enjeux sont liés à l’emploi d’expressions régulières ?

Toute personne travaillant avec des instructions de regex a une grande liberté, car il y a toujours plusieurs options de solution pour chaque mission devant être résolue avec une expression régulière. Il n’est néanmoins pas toujours avantageux qu’un résultat souhaité puisse être obtenu de différentes manières :

Vous pouvez par exemple garder les instructions à un niveau très général pour atteindre l’objectif visé quoi qu’il arrive. Si vous voulez en revanche le résultat le plus précis possible, vous devrez impérativement formuler un modèle de regex spécifique. Il est également conseillé de faire attention à la longueur : plus une expression régulière est concise, plus sa durée de traitement est courte. Elle doit néanmoins toujours être lisible. Car si vous souhaitez modifier ultérieurement les expressions régulières utilisées, vous devrez faire face à un obstacle de taille si les instructions initiales sont trop compliquées, et qui plus est sans commentaire.

Lors de la création d’expressions régulières, il s’agit donc de trouver un rapport optimal entre la concision et la spécificité.

Quelles règles syntaxiques s’appliquent aux expressions régulières ?

Comme indiqué précédemment, les expressions régulières peuvent être employées dans divers langages (par exemple Perl, Python, Ruby, JavaScript, XML ou HTML), l’utilisation ou la fonction pouvant alors être très différentes. Dans JavaScript, les modèles de regex sont par exemple utilisés pour les méthodes String search(), match() ou replace(), alors que les expressions dans les documents XML servent à limiter les contenus des éléments. En matière de syntaxe, il n’y a quasiment aucune différence entre les différents langages de programmation et de balisage pour ce qui tourne autour des expressions régulières :

Une expression régulière peut ainsi se diviser en trois parties au maximum, indépendamment du langage dans lequel elle est utilisée :

Motif (modèle de recherche) L’élément central est le motif, autrement dit le modèle de recherche général. Il peut s’agir soit exclusivement de caractères simples, soit d’une combinaison de caractères simples et de caractères spéciaux, comme expliqué au chapitre précédent.
Délimiteur (caractère de séparation) Le début et la fin du motif sont caractérisés par le délimiteur. En principe, tous les caractères non alphanumériques (à l’exception de la barre oblique inversée) peuvent être considérés comme des caractères de séparation. PHP prévoit par exemple comme délimiteurs au choix des hashtags (#motif#), des pourcentages (%motif%), des signes plus (+motif+) ou des tildes (~motif~). Dans la plupart des langages, on utilise cependant des guillemets droits ("motif") ou des barres obliques (/motif/).
Modificateur Les modificateurs peuvent être ajoutés à un modèle de recherche afin de modifier l’expression régulière. Il y a par exemple le modificateur i, qui supprime la sensibilité à la casse. Celle-ci veille à ce que l’écriture en lettres capitales et minuscules joue un rôle et s’applique de manière standard à toutes les expressions régulières.

Les caractères spéciaux syntaxiques types pouvant étendre les motifs à des options données comprennent notamment :

Caractères spéciaux syntaxiques des regex Fonction
[] Une paire de crochets caractérise une classe de caractères qui existe toujours pour un seul caractère dans un modèle de recherche.
() Une paire de parenthèses caractérise un groupe de caractères se composant d’un ou de plusieurs caractères et pouvant être imbriqués.
- Sert d’indication de plage (de [… ] à […]) quand il se trouve entre deux caractères normaux
^ Limiter la recherche au début d’une ligne (autre fonction : inverseur dans les classes de caractères)
$ Limiter la recherche à la fin d’une ligne
. Correspond à n’importe quel caractère
* Le nombre de caractères, de classes ou de groupes devant un astérisque peut être n’importe lequel (y compris zéro).
+ Le caractère, la classe ou le groupe devant un signe plus doit être présent(e) au moins une fois.
? Le caractère, la classe ou le groupe devant un point d’interrogation est optionnel(le) et ne peut apparaître qu’une fois au maximum.
{n} Le caractère, la classe ou le groupe précédent(e) apparaît exactement n fois.
{n,m} Le caractère, la classe ou le groupe précédent(e) apparaît au moins n fois et au maximum m fois.
{n,} Le caractère, la classe ou le groupe précédent(e) apparaît au moins n fois ou plus.
\b Tenir compte de la limite de mots lors de la recherche
\B Ignorer la limite de mots lors de la recherche
\d N’importe quel chiffre ; abréviation de la classe de caractères [0-9]
\D N’importe quel caractère autre qu’un chiffre ; abréviation de la classe de caractères [^0-9]
\w N’importe quel caractère alphanumérique ; abréviation de la classe de caractères [a-zA-Z_0-9]
\W N’importe quel caractère autre qu’un caractère alphanumérique ; abréviation de la classe de caractères [^\w]

Tutoriel : les possibilités des expressions régulières expliquées à l’aide d’exemples

Après un résumé des bases des regex dans les paragraphes précédents de cet article, le tutoriel suivant doit montrer le fonctionnement des chaînes de caractères pratiques. Les différentes possibilités et astuces syntaxiques sont indiquées ici à l’aide d’exemples concrets d’expressions régulières, tant pour des expressions simples que complexes.

Expressions régulières à un élément

La forme de regex la plus simple est un modèle de recherche ne prévoyant qu’un seul élément à trouver. Dans la mesure où vous ne cherchez pas un élément concret, une expression régulière à un élément par exemple peut être définie sans problème à l’aide d’une classe de caractères. Avec l’expression suivante, les résultats possibles sont les chiffres « 1 », « 2 », « 3 », « 4 », « 5 », « 6 » ou « 7 » :

[1234567]

Étant donné que les nombres se succèdent directement dans ce cas, la forme simplifiée suivante serait également possible :

[1-7]

Si l’expression régulière est modifiée de sorte que le chiffre « 4 » est exclu de la recherche, vous pouvez également utiliser la variante simplifiée avec le signe moins :

[1-35-7]
Note

Les différents caractères d’un motif de regex ne sont pas séparés par des espaces.

Expressions régulières à plusieurs éléments

Même pour une expression régulière à plusieurs éléments, vous pouvez travailler avec des classes de caractères afin d’avoir différents résultats possibles. Si l’expression comprend par exemple deux éléments pour lesquels différents résultats sont envisageables, il vous suffit d’ordonner deux classes de caractères correspondantes l’une à la suite de l’autre :

[1-7][a-c]

Une des lettres « a », « b » ou « c » suit ainsi le premier élément, un chiffre compris entre « 1 » et « 7 ». Comme indiqué précédemment, les minuscules sont obligatoires. Avant de traiter ici les modificateurs, vous pouvez déjà vous attaquer à la petite modification suivante de l’expression Inclure les majuscules :

[1-7][a-cA-C]

Expressions régulières avec des éléments en option

Que vous cherchiez plusieurs éléments dans une seule expression régulière ou à l’aide de plusieurs groupes de caractères, il est possible que des éléments donnés ne puissent ou ne doivent être contenus que sous certaines conditions. Cela serait par exemple envisageable dans le cas d’une expression régulière devant filtrer tous les numéros de maison. Le numéro de maison n’est parfois composé que d’un seul chiffre, mais les résultats obtenus comprennent aussi des numéros se composant de deux ou même de trois chiffres. Il y a qui plus est des adresses pour lesquelles une lettre est ajoutée au numéro de maison. Cet ensemble de combinaisons possibles peut être couvert idéalement par les instructions de regex suivantes :

[1-9][0-9]?[0-9]?[a-z]?

Le seul élément obligatoire de ce modèle de recherche est un chiffre compris entre « 1 » et « 9 ». Deux chiffres compris entre « 0 » et « 9 » suivis d’une lettre quelconque peuvent être choisis en option, ce qui est caractérisé respectivement par le point d’interrogation placé après.

Alors que la construction pour des numéros à trois chiffres suivis d’une lettre supplémentaire est encore assez claire, il n’en est rien pour des numéros allant jusqu’à dix chiffres. Dans ce cas, il est recommandé d’utiliser des accolades, comme dans l’exemple suivant d’expressions régulières :

[1-9][0-9]{0,9}

Comme dans l’exemple précédent, la recherche se concentre tout d’abord sur un chiffre compris entre « 1 » et « 9 », puis soit aucun, soit jusqu’à neuf chiffres compris entre « 0 » et « 9 ». Le résultat peut donc aller jusqu’à dix chiffres.

Expression régulière avec n’importe quelle fréquence des répétitions

Dans les exemples précédents d’expressions à un ou plusieurs éléments, les nombres minimal et maximal de caractères étaient connus. Il existe néanmoins bien évidemment des cas dans lesquels la quantité de caractères d’une regex ne doit pas être définie exactement à l’avance. Les paramètres requis sont alors l’astérisque et le signe plus, qui permettent d’autoriser un nombre quelconque de répétitions d’un caractère, d’une classe ou d’un groupe de caractères. Toutes les chaînes de caractères peuvent ainsi être saisies avec n’importe quelle quantité de chiffres (même « zéro »), par exemple avec l’expression régulière suivante :

[0-9]*

La même remarque s’applique quand une combinaison concrète de caractères est recherchée, dans laquelle un (ou plusieurs) caractère(s) peut/peuvent être répété(s) x fois. Comme dans l’exemple suivant :

an*

Les correspondances possibles sont dans ce cas aussi bien le mot « amidon » que « anémone » et « annuaire ». Si le premier résultat doit être exclu ou si le caractère spécifié doit apparaître au moins une fois, il faut utiliser au lieu de cela le signe plus :

an+

Inverser les classes de caractères

Si vous voulez utiliser des expressions régulières avec des classes de caractères qui représentent en principe un ou plusieurs caractères, mais qui excluent ici un ou plusieurs caractères donnés comme résultat, vous avez besoin de l’inverseur « ^ » (accent circonflexe). Il est toujours entre les parenthèses d’une classe de caractères et n’est valable qu’entre ces parenthèses. L’instruction suivante donne un bon exemple de classe de caractères inversée :

b[^u]lle

Dans le cas du deuxième caractère, il peut dans ce cas s’agir d’un caractère quelconque sauf « u » ; le mot « balle » offre donc les correspondances requises. Le mot « bulle » en revanche non, car il ne correspond pas à l’expression régulière.

Caractères de substitution

Les expressions régulières permettent également de travailler avec des caractères de substitution qui peuvent se trouver au choix au milieu d’un modèle de recherche pour un, aucun ou plusieurs caractère(s) (suivant le métacaractère utilisé). Le caractère de substitution est ici créé par un point que vous combinez avec le caractère spécial énuméré auparavant pour les répétitions quand un résultat autre qu’un caractère individuel est souhaité. Des expressions régulières de ce type permettent par exemple d’analyser une base de données à la recherche d’une personne dont vous connaissez certes le nom et le prénom, mais dont vous ne savez pas si elle est enregistrée avec un deuxième prénom :

Jean .*Dupont

Les résultats possibles sont dans ce cas aussi bien « Jean Eric Dupont » (ainsi que n’importe quelle autre combinaison avec un deuxième prénom), « Jean E. Dupont ou « Jean Dupont ». Si vous ne devez tenir compte que de variantes avec un deuxième prénom, utilisez un signe plus à la place de l’astérisque :

Jean .+Dupont

Un bon exemple d’utilisation pertinente d’un caractère de substitution pour un caractère individuel est le modèle de recherche suivant, qui correspond aussi bien à « bal » qu’à « bol » :

b.l

Solutions alternatives

Vous avez la possibilité de formuler des expressions régulières de manière à avoir deux ou plusieurs solutions alternatives pour une correspondance. Il faut dans ce cas séparer les solutions alternatives par une barre verticale, comme dans l’exemple suivant :

Fraise|Framboise

« Fraise » comme « Framboise » offrent donc tous deux une correspondance.

En variante, il est également possible d’intervenir au milieu de mots ou de séquences de caractères en recourant à des groupes :

(Lun|Mar|Mercre|Jeu|Vendre|Same)di|Dimanche

Dans cet exemple, chaque jour de la semaine est un résultat potentiel, tous les noms de jours de la semaine se terminant par « di » proposés en alternative étant saisis correctement grâce au regroupement entre parenthèses, même dans la forme abrégée.

Groupes

Les groupes de caractères comme dans l’exemple du paragraphe précédent sont considérés au même titre que les classes de caractères comme des éléments structurels d’expressions régulières. Ils peuvent être définis par une paire de parenthèses et représentent en principe un motif composé d’un ou de plusieurs caractères – stricto sensu, chaque regex est donc un groupe, la caractérisation par les parenthèses étant dans ce cas supprimée. Dans les expressions, les groupes accordent la possibilité d’appliquer des opérateurs comme le caractère de séparation ou de répétition (signe plus ou astérisque) à une expression partielle souhaitée :

ab(cd)+

La répétition quelconque souhaitée s’applique donc dans ce cas au groupe de caractères « cd », alors qu’elle ne se serait appliquée pour la même orthographe sans guillemets qu’au « d ». Dans une regex, il n’y a aucune limitation par rapport à la quantité de groupes contenus.

Imbrications

Non seulement un nombre de groupes quelconque peut exister dans une expression régulière, mais autant de groupes que souhaité peuvent s’imbriquer les uns dans les autres afin d’exprimer des relations complexes entre des caractères simples et des caractères spéciaux, même sans chaînes de caractères inutilement longues. Un exemple de cela est le modèle de regex suivant, qui a comme résultats possibles quatre modèles automobiles « Golf VW », « Polo VW », « Fiat Punto » ou « Fiat Panda » :

((Golf|Polo) VW|Fiat (Punto|Panda))

Limites de mots

S’il faut tenir compte de limites de mots, autrement dit du début ou de la fin d’une séquence alphanumérique pour l’application d’une expression régulière, un métacaractère doit le spécifier. De nombreux langages utilisent pour cela la combinaison « \b » qui peut précéder le modèle de recherche, le suivre, ou le précéder et le suivre.

La première variante prescrit que la séquence de recherche se trouve au début du mot :

\bun

Une correspondance pour cette expression régulière est par exemple le mot « uniforme ». Le mot « muni » ne peut en revanche pas être un résultat possible, car la lettre « m » précède le caractère recherché. Pour inverser la tendance, utilisez la variante n° 2 et faites-la suivre du caractère spécial :

un\b

Avec la troisième option, vous définissez les deux mots limites comme une condition. Le seul résultat possible dans ce cas précis est donc l’article indéfini (ou le pronom/chiffre) « un » :

\bun\b

Annulation de la méta-signification de caractères spéciaux

Au paragraphe précédent, la barre oblique inversée avait pour fonction que le « m » suivant ne soit pas considéré comme une lettre, mais comme un métacaractère. Si on le combine aux caractères qui font partie de manière standard des caractères spéciaux syntaxiques des regex, il a exactement l’effet inverse : le caractère est traité comme n’importe quel autre caractère littéral. Cette possibilité vous permet aussi de rechercher sans problème une date concrète avec une expression régulière :

11\.10\.2019

La date « 11.10.2019 » est la seule chaîne de caractères correspondant dans ce cas aux critères de recherche demandés. Sans la barre oblique inversée, les deux points seraient considérés comme les caractères de substitution d’un caractère quelconque, rendant de fait également possible des résultats comme « 1101092019 » ou « 11a10b2019 ».

« Alléger » des expressions régulières gourmandes

L’emploi de quantificateurs (« ? », « + », « * », « {} ») veille de manière standard à ce qu’une expression soit « gourmande » et à chercher le maximum de correspondances possibles. Étant donné que ce comportement n’est pas toujours souhaitable, les quantificateurs peuvent être spécifiés dans une expression régulière de manière à limiter leur « gourmandise ». L’exemple suivant permet d’expliquer plus concrètement ce processus de modification :

A.*B

Appliquée à la séquence de caractères suivante « ABCDEB », cette expression gourmande n’arrêterait pas la recherche à « AB », mais enregistrerait comme résultat l’ensemble de la séquence de caractères. Si la recherche doit en revanche s’interrompre après le premier « B » trouvé, il faut procéder à la modification évoquée. Dans de nombreux langages (notamment Perl, Tcl, HTML), un point d’interrogation est placé à cet effet après les quantificateurs :

A.*?B

En variante, l’expression gourmande initiale peut également être remplacée par l’expression équivalente « non gourmande » pour arriver au même résultat :

A[^B]*B
Note

La limitation des expressions régulières gourmandes complique le traitement d’un modèle de recherche et est donc associée à une durée de recherche plus longue.