Cliquez sur un bouton pour naviguer

3. Syntaxe

L'expression régulière la plus simple est un unique caractère. Elle correspond exactement à ce caractère. Une séquence de caractères correspond à une chaîne avec exactement la même succession de caractères :

  'a' matchesRegex: 'a' -- true
  'foobar' matchesRegex: 'foobar' -- true
  'blorple' matchesRegex: 'foobar' -- false

Le paragraphe précédant introduisait une expression régulière élémentaire (un caractère) et un opérateur (la séquence). Les opérateurs sont appliqués à des expressions régulières pour produire des expressions régulières plus complexes. La séquence (placement des éléments les uns à côté des autres) est un opérateur en quelque sorte invisible bien qu'il soit le plus courant.

Un opérateur plus visible est l'étoile. Une expression régulière suivie par un astérisque (étoile) reconnaît un nombre quelconque d'occurrences (y-compris 0) dans la chaîne à traiter. Par exemple :

'ab' matchesRegex: 'a*b' -- true
  'aaaaab' matchesRegex: 'a*b' -- true
  'b' matchesRegex: 'a*b' -- false
  'aac' matchesRegex: 'a*b' -- false: 'b' n'a pas de correspondance

La préséance d'une étoile est supérieure à celle d'une séquence. L'étoile s'applique à la sous-expression la plus petite qui la précède. Par exemple, 'ab*' signifie a suivi de zéro ou plusieurs occurrence de b, et non zéro ou plusieurs occurrence de ab :

'abbb' matchesRegex: 'ab*' -- true
  'abab' matchesRegex: 'ab*' -- false

Pour reconnaître 0 ou plus d'occurrence de 'ab', 'ab' doit être mis entre parenthèses:
'abab' matchesRegex: '(ab)*' -- true
  'abcab' matchesRegex: '(ab)*' -- false : 'c' est l'intrus

Deux autre opérateurs similaires à '*' sont '+' et '?'. '+' reconnaît 1 ou plusieurs occurrences de l'expression originale. '?' ('option') reconnaît zéro ou une occurrence (mais pas plus).

'ac' matchesRegex: 'ab*c' -- true
  'ac' matchesRegex: 'ab+c' -- false : il faut au moins un 'b'
  'abbc' matchesRegex: 'ab+c' -- true
  'abbc' matchesRegex: 'ab?c' -- false : trop de 'b'

Comme nous l'avons vu, les caractères '*', '+', '?', '(' et ')' ont une signification particulière dans les expressions régulières. Si l'une d'entre elles doit être utilisée littéralement, elle doit être précédée par un antislash. De ce fait, l'antislash est aussi un caractère particulier et doit être doublé pour être utilisé littéralement. Nous verrons par la suite des caractères aux caractéristiques semblables.

'ab*' matchesRegex: 'ab*' -- false : l'étoile dans la chaîne de droite à une signification spéciale
  'ab*' matchesRegex: 'ab\*' -- true
  'a\c' matchesRegex: 'a\\c' -- true

Le dernier opérateur est '|' qui signifie 'ou'. Il se place entre 2 expressions régulières ; l'expression résultante est reconnue si l'une des 2 expressions l'est. Il a la plus faible préséance. Par exemple, 'ab*|ba*' signifie a suivi par un nombre quelconque de b, ou b suivi par un nombre quelconque de a :

'abb' matchesRegex: 'ab*|ba*' -- true
  'baa' matchesRegex: 'ab*|ba*' -- true
  'baab' matchesRegex: 'ab*|ba*' -- false

L'exemple suivant est un peu plus compliqué. L'expression reconnaît le nom de toutes les fonctions Lisp du type 'caar', 'cadr'... :

c(a|d)+r  

Il est possible d'écrire une expression reconnaissant une chaîne vide, par exemple 'a|'. Toutefois c'est une erreur d'appliquer '*', '+' ou '?' à une telle expression : '(a|)*' est une expression non valide.

Jusqu'ici nous n'avons utilisé que des caractères isolés qui sont les plus petits composants des expressions régulières. Il y en a d'autres, plus intéressants.

Une classe de caractères est une chaîne de caractères entre crochets. Elle reconnaît un seul caractère s'il existe dans la chaîne entre crochets. Par exemple, '[01]' correspond soit à 0 soit à 1 :

'0' matchesRegex: '[01]' -- true
  '3' matchesRegex: '[01]' -- false
  '11' matchesRegex: '[01]' -- false : une classe de caractères ne reconnaît qu'un seul caractère

En utilisant l'opérateur '+' nous pouvons construire un détecteur de nombres binaires :

'10010100' matchesRegex: '[01]+' -- true
  '10001210' matchesRegex: '[01]+' -- false

Si le premier caractère après le crochet ouvrant est un '^', la classe de caractères est complémentée : elle reconnaît un seul caractère ne figurant pas entre les crochets :

'0' matchesRegex: '[^01]' -- false
  '3' matchesRegex: '[^01]' -- true

Dans une classe, 2 caractères séparés par un tiret ('-') déterminent un intervalle. C'est la même chose que de lister tous les caractères qui les séparent  : '[0-9]' est identique à '[0123456789]'.

Les caractères spéciaux à l'intérieur d'une classe sont :'^', '-' et ']'. Les exemples suivant montrent comment les utiliser littéralement :

[01^] -- mettre l'accent n'importe où excepté en première position
  [01-] -- mettre le tiret à la fin
  []01] -- mettre le crochet fermant en première position
  [^]01]       (les classes vides et universelles ne peuvent pas être spécifiées)

Les expressions régulières peuvent aussi comprendre les séquences d'échappement par antislash suivantes :

\w n'importe quel caractère constituant habituellement un mot (identique à [a-zA-Z0-9_])
  \W n'importe quel caractère sauf un de ceux constituant habituellement un mot
  \d un chiffre (identique à [0-9])
  \D n'importe quel caractère sauf un chiffre
  \s un caractère d'espacement
  \S n'importe quel caractère sauf un caractère d'espacement

Ces séquences sont également autorisées dans les classes de caractères : '[\w+-]' signifie n'importe quel caractère qui est soit un constituant d'un mot, soit le caractère '+', soit le caractère '-'.

Les classes de caractères peuvent aussi comprendre les expressions suivantes de POSIX (compatibles avec grep) :

[:alnum:] n'importe quel caractère alphanumérique
  [:alpha:] n'importe quel caractère alphabétique
  [:cntrl:] n'importe quel caractère de contrôle. Dans cette version les caractères de code ascii inférieur à 32
  [:digit:] n'importe quel chiffre
  [:graph:] n'importe quel caractère graphique. Dans cette version les caractères de code ascii supérieur à 32
  [:lower:] tout caractère minuscule
  [:print:] tout caractère imprimable. Identique à [:graph:] dans cette version
  [:punct:] n'importe quel caractère de ponctuation
  [:space:] n'importe quel caractère d'espacement
  [:upper:] tout caractère majuscule
  [:xdigit:] tout caractère hexadécimal

Notez que ces éléments sont des composants des classes de caractères, c'est-à-dire qu'il peuvent apparaître a l'intérieur d'une paire de crochets supplémentaire pour former une expression régulière valide. Par exemple, une chaîne non-vide de chiffres peut être représentée de cette façon : '[[:digit:]]+'.

Les opérateurs et les expressions primitives que nous venons de voir sont communes à de nombreuses implémentations des expressions régulières. Les expressions primitives suivantes sont particulières à l'implémentation Smalltalk.

Une séquence de caractères entre deux-points (':') est traitée comme un sélecteur unaire qui est supposé être compris par la classe Smalltalk Character. Un caractère reconnaît une telle expression si elle retourne true à un message utilisant ce sélecteur. Ceci autorise une manière plus lisible et plus efficace de spécifier des classes de caractères. Par exemple, '[0-9] est équivalente à ':isDigit:', mais cette dernière est plus efficace. De manière similaire aux classes de caractères des expressions régulières, ces sélecteurs Smalltalk peuvent être complémentés : ':^isDigit:' reconnaît un élément de la classe Character qui retourne false à la méthode #isDigit et est donc équivalent à '[^0-9]'.

Pour résumer, nous avons jusqu'à présent rencontré les manières suivantes d'écrire une expression régulière qui reconnaît une chaîne non-vide de chiffres :

[0-9]+
  \d+
  [\d]+
  [[:digit:]]+
  :isDigit:+

Le dernier groupe d'expressions primitives comprend :

. reconnaît n'importe quel caractère excepté une nouvelle ligne (newline)
  ^ reconnaît une chaîne vide en début de ligne
  $ reconnaît une chaîne vide en fin de ligne
  \b reconnaît une chaîne vide en limite de mot
  \B reconnaît une chaîne vide qui n'est pas à la limite d'un mot
  \< reconnaît une chaîne vide au début d'un mot
  \> reconnaît une chaîne vide en fin d'un mot

'axyzb' matchesRegex: 'a.+b' -- true
 

'ax
    zb' matchesRegex: 'a.+b'

-- false (un saut de ligne n'est pas reconnu par '.')

EXEMPLES

Comme l'introduction le précisait, un usage important des expressions régulières est la validation de saisie. Les exemples ci-dessous le démontrent.
Essayez-les en saisissant quelque chose entre les apostrophes et affichez-en le résultat. Essayez également d'imaginer le code Smalltalk nécessaire pour coder ces contrôles « à la main ». La plupart des expressions suivantes auraient pu être écrite de plusieurs autres manières.

Vérifier si une chaîne représente un nombre entier non négatif :

' ' matchesRegex: ':isDigit:+'
ou  
  ' ' matchesRegex: '[0-9]+'
ou  
  ' ' matchesRegex: '\d+'

Vérifier si une chaîne représente un nombre entier précédé par un signe optionnel :

' ' matchesRegex: '(\+|-)?\d+'

Vérifier si une chaîne représente un nombre décimal avec au moins un chiffre après le point décimal :

' ' matchesRegex: '(\+|-)?\d+(\.\d+)?'

La même chose mais autorise une notation du type : '123.' :

' ' matchesRegex: '(\+|-)?\d+(\.\d*)?'

Détecte si une chaîne est un nom : un mot avec la première lettre en capitale, sans espace ni chiffre :

' ' matchesRegex: '[A-Z][A-Za-z]*'

La même réécrite façon Smalltalk :

' ' matchesRegex: ':isUppercase::isLetter:*'

Reconnaître une date au format MMM JJ, 19YY avec un nombre quelconque d'espaces :

' ' matchesRegex: '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ]+(\d\d?)[ ]*,[ ]*19(\d\d)'

Notez les parenthèses autour de certains composants dans l'expression ci-dessus. Comme la section « Usage » le montre, elles nous permettent d'obtenir les valeurs réelles des chaînes qui auront été détectées.

Pour terminer cette série d'exemples, on revient aux nombres : voici un détecteur de format numérique en général :

' ' matchesRegex: '(\+|-)?\d+(\.\d*)?((e|E)(\+|-)?\d+)?'

Dernière modification le 25-08-2002