Compiler une fois, puis chercher
Écrivez les motifs comme des littéraux de chaîne brute entre accents graves. Dans une chaîne ordinaire entre guillemets doubles, chaque antislash doit être doublé ("\\d+"), ce qui devient vite illisible.
regexp.MustCompile provoque un panic si le motif est invalide, ce que vous voulez pour un motif présent dans votre code source : une faute de frappe échoue immédiatement au démarrage, pas à la première requête. Pour les motifs qui viennent d'utilisateurs ou de la configuration, utilisez regexp.Compile et gérez l'erreur :
re, err := regexp.Compile(userPattern)
if err != nil {
return fmt.Errorf("bad pattern: %w", err)
}
Compilez une seule fois. La compilation coûte bien plus cher que la recherche. Un regexp.MustCompile dans une fonction exécutée à chaque requête ou à chaque ligne refait ce travail à chaque fois. Placez le *regexp.Regexp compilé dans une var au niveau du package ou dans un champ de struct. Une regexp compilée peut être utilisée par de nombreuses goroutines à la fois sans risque.
regexp.MatchString(pattern, s) compile et cherche en un seul appel. C'est acceptable pour une vérification ponctuelle et du gaspillage dans une boucle.
Trouver des correspondances
Les noms des méthodes suivent un schéma : Find + All? + String? + Submatch? + Index?.
| Partie | Signification |
|---|---|
All | toutes les correspondances sans chevauchement ; prend une limite n (-1 pour toutes) |
String | travaille sur une string ; sans elle, la méthode prend et renvoie des []byte |
Submatch | renvoie aussi les groupes de capture |
Index | renvoie des positions en octets au lieu du texte |
FindString renvoie "" quand il n'y a pas de correspondance, ce qu'on ne peut pas distinguer d'une correspondance avec une chaîne vide. Quand le motif peut correspondre à un texte vide, utilisez FindStringIndex (qui renvoie nil sans correspondance) ou MatchString d'abord. Les variantes All renvoient nil quand rien ne correspond.
Groupes de capture
Les parenthèses capturent. FindStringSubmatch renvoie la correspondance complète à l'indice 0, puis une entrée par groupe :
Vérifiez toujours nil avant d'indexer le résultat ; sans correspondance, m[1] provoque un panic.
(?:...) groupe sans capturer, pour l'alternative ou la répétition : (?:ab)+. Les groupes nommés s'écrivent (?P<name>...), et depuis Go 1.22 aussi (?<name>...).
Remplacer
Un piège classique avec les références de groupe : "$1x" est lu comme un groupe nommé 1x, qui n'existe pas, et se développe en chaîne vide. Écrivez "${1}x".
Pour une chaîne fixe, strings.ReplaceAll, strings.Contains et strings.Split sont plus simples et plus rapides qu'une regexp. Tournez-vous vers regexp quand le texte cherché a une forme plutôt qu'une valeur fixe.
Référence rapide de la syntaxe
Go utilise la syntaxe RE2, qui couvre les fonctionnalités familières du style Perl :
| Syntaxe | Correspond à |
|---|---|
. | n'importe quel caractère sauf le retour à la ligne (avec (?s), le retour à la ligne aussi) |
\d \w \s | chiffre, caractère de mot [0-9A-Za-z_], espace blanc (ASCII uniquement) |
\D \W \S | les négations |
[abc] [^abc] [a-z] | classes de caractères |
\pL \p{Greek} | classes Unicode : n'importe quelle lettre, n'importe quel caractère grec |
* + ? {n,m} | répétition, gourmande |
*? +? ?? | répétition, paresseuse |
^ $ | début et fin du texte (de la ligne, avec (?m)) |
\b | limite de mot (ASCII) |
a|b | alternative |
(?i) | insensible à la casse depuis ce point jusqu'à la fin du groupe englobant ; généralement écrit au début du motif |
\d et \w ne correspondent qu'à l'ASCII. Pour « n'importe quelle lettre dans n'importe quelle langue », utilisez \pL, et pour n'importe quel chiffre Unicode, \p{Nd}. regexp.QuoteMeta(s) échappe tous les caractères spéciaux de s, ce dont vous avez besoin pour construire un motif à partir d'une saisie utilisateur.
Ce que RE2 ne sait pas faire
Le regexp de Go garantit que la recherche prend un temps linéaire par rapport à la longueur de l'entrée. Les fonctionnalités qui casseraient cette garantie ne sont pas prises en charge :
- Pas de lookahead ni de lookbehind :
(?=...),(?!...),(?<=...),(?<!...)sont des erreurs de compilation. Comme Go 1.22 a commencé à accepter(?<name>...)pour les groupes nommés, un lookbehind échoue désormais avec le message déroutantinvalid named capture, comme le montre le programme ci-dessous. - Pas de références arrière :
(\w)\1pour trouver une lettre doublée n'est pas possible. - Pas de quantificateurs possessifs ni de groupes atomiques.
Le contournement est presque toujours le même : capturez un peu plus que nécessaire, puis filtrez ou découpez en Go. La contrepartie, c'est qu'une regexp Go ne peut pas être poussée dans un retour arrière catastrophique. Un motif comme (a+)+$, qui peut figer un moteur PCRE sur une entrée courte, s'exécute ici en temps linéaire, ce qui compte quand le motif ou l'entrée viennent de l'extérieur.
Erreurs courantes
- Compiler dans une boucle ou un handler. Compilez une fois dans une variable au niveau du package.
- Des motifs entre guillemets doubles.
"\d"n'est même pas une chaîne Go valide ; utilisez des accents graves. - Oublier les ancres dans une validation.
\d{5}correspond à l'intérieur de"abc123456xyz". Utilisez^\d{5}$. - Indexer un résultat de sous-correspondance sans vérifier
nil. - S'attendre à ce que
\wou\bcomprennent le texte non ASCII. Utilisez des classes Unicode comme\pL. - Utiliser regexp pour des chaînes fixes. Le package
stringsest plus clair et plus rapide.
Questions fréquentes
Comment vérifier qu'une chaîne correspond à une regex en Go ?
Compilez le motif une fois avec regexp.MustCompile, en l'écrivant comme chaîne brute entre accents graves pour que les antislashs n'aient pas besoin d'échappement, puis appelez re.MatchString(s). Sans ancres (^ et $), MatchString renvoie true si le motif correspond n'importe où dans la chaîne.
Le regexp de Go prend-il en charge le lookahead et le lookbehind ?
Non. Le regexp de Go utilise la syntaxe RE2, qui n'a ni lookahead, ni lookbehind, ni références arrière. En échange, la recherche s'exécute en temps linéaire par rapport à la taille de l'entrée, donc un motif ou une entrée malveillants ne peuvent pas bloquer votre programme. Utilisez plutôt des groupes de capture et un peu de code Go, ou découpez la vérification en deux regex.
Quelle est la différence entre regexp.Compile et regexp.MustCompile ?
Compile renvoie le motif compilé et une erreur. MustCompile provoque plutôt un panic sur un motif invalide. Utilisez MustCompile pour les motifs écrits dans votre code source, typiquement dans une variable au niveau du package, pour qu'une faute de frappe échoue au démarrage. Utilisez Compile pour les motifs qui viennent d'utilisateurs ou de fichiers de configuration.
Comment récupérer les groupes de capture d'une regex en Go ?
Utilisez FindStringSubmatch, qui renvoie une slice dont l'indice 0 est la correspondance complète et les indices 1, 2, ... les groupes, ou nil s'il n'y a pas de correspondance. Pour toutes les correspondances, utilisez FindAllStringSubmatch(s, -1). Les groupes nommés (?P<year>\d{4}) se retrouvent avec re.SubexpIndex("year").