Le paquet regexp prend en charge les expressions régulières en Go.
La syntaxe des expressions régulières acceptées est la même syntaxe générale que celle utilisée par Perl, Python et d'autres langages.
Les motifs de recherche comme les textes d'entrée sont interprétés en UTF-8.
Quand on utilise des accents graves (`) to make strings, backslashes (\) don't have any special meaning and don't mark the beginning of special characters like tabs \t or newlines \n :
"\t\n" // regular string literal with 2 characters: a tab and a newline
`\t\n`// raw string literal with 4 characters: two backslashes, a 't', and an 'n'
C'est pourquoi il est préférable d'utiliser les accents graves pour écrire des expressions régulières, car on n'a alors pas besoin d'échapper les barres obliques inverses :
"\\" // string with a single backslash
`\\` // string with 2 backslashes
RegExp
Pour utiliser une expression régulière, il faut d'abord compiler le motif sous forme de string.
La compilation consiste ici à prendre le motif de l'expression régulière sous forme de string et à le convertir en une représentation interne plus facile à manipuler.
Il suffit de compiler chaque motif une seule fois ; ensuite, on peut utiliser autant de fois que nécessaire la version compilée de l'expression régulière.
Le type regexp.Regexp représente une expression régulière compilée.
On peut compiler un motif sous forme de string en un regexp.Regexp grâce à la fonction regexp.Compile.
Cette fonction renvoie nil et une erreur si la compilation échoue :
re, err := regexp.Compile(`(a|b)+`)
fmt.Println(re, err) // => (a|b)+ <nil>
re, err = regexp.Compile(`a|b)+`)
fmt.Println(re, err) // => <nil> error parsing regexp: unexpected ): `a|b)+`
La fonction MustCompile est une alternative pratique à Compile :
re = regexp.MustCompile(`[a-z]+\d*`)
Avec cette fonction, il n'est pas nécessaire de gérer une erreur.
MustCompile ne doit être utilisée que lorsqu'on est certain que le motif se compile, sinon le programme panique.
Il existe 16 méthodes de Regexp qui appliquent une expression régulière et identifient le texte correspondant.
Leurs noms correspondent à cette expression régulière :
Find(All)?(String)?(Submatch)?(Index)?
All est présent, la méthode recherche les correspondances successives sans chevauchement de l'expression entière.String est présent, l'argument est une string ; sinon, c'est un slice d'octets ; les valeurs de retour sont adaptées en conséquence.Submatch est présent, la valeur de retour est un slice qui identifie les sous-correspondances successives de l'expression.Index est présent, les correspondances et les sous-correspondances sont identifiées par des paires d'indices d'octets dans la string d'entrée.Il existe aussi des méthodes pour :
Au total, le paquet regexp définit plus de 40 fonctions et méthodes.
On va illustrer ci-dessous l'utilisation de quelques méthodes.
Consulte la documentation de l'API pour plus de détails sur ces fonctions et sur les autres.
MatchString
La méthode MatchString indique si une string contient au moins une correspondance de l'expression régulière.
re = regexp.MustCompile(`[a-z]+\d*`)
b = re.MatchString("[a12]") // => true
b = re.MatchString("12abc34(ef)") // => true
b = re.MatchString(" abc!") // => true
b = re.MatchString("123 456") // => false
FindString
La méthode FindString renvoie une string contenant le texte de la correspondance la plus à gauche de l'expression régulière.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.FindString("[a12]") // => "a12"
s = re.FindString("12abc34(ef)") // => "abc34"
s = re.FindString(" abc!") // => "abc"
s = re.FindString("123 456") // => ""
FindStringSubmatch
La méthode FindStringSubmatch renvoie un slice de strings contenant le texte de la correspondance la plus à gauche de l'expression régulière ainsi que les correspondances, s'il y en a, de ses sous-expressions.
On peut s'en servir pour identifier les strings qui correspondent aux groupes de capture.
Une valeur de retour de nil indique qu'il n'y a pas de correspondance.
re = regexp.MustCompile(`[a-z]+(\d*)`)
sl = re.FindStringSubmatch("[a12]") // => []string{"a12","12"}
sl = re.FindStringSubmatch("12abc34(ef)") // => []string{"abc34","34"}
sl = re.FindStringSubmatch(" abc!") // => []string{"abc",""}
sl = re.FindStringSubmatch("123 456") // => <nil>
ReplaceAllString
La méthode re.ReplaceAllString(src,repl) renvoie une copie de src, en remplaçant les correspondances de l'expression régulière re par la string de remplacement repl.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.ReplaceAllString("[a12]", "X") // => "[X]"
s = re.ReplaceAllString("12abc34(ef)", "X") // => "12X(X)"
s = re.ReplaceAllString(" abc!", "X") // => " X!"
s = re.ReplaceAllString("123 456", "X") // => "123 456"
Split
La méthode re.Split(s,n) découpe un texte s en sous-chaînes séparées par l'expression et renvoie un slice des sous-chaînes comprises entre ces correspondances.
La valeur n détermine le nombre maximal de sous-chaînes à renvoyer.
Si n<0, la méthode renvoie toutes les sous-chaînes.
re = regexp.MustCompile(`[a-z]+\d*`)
sl = re.Split("[a12]", -1) // => []string{"[","]"}
sl = re.Split("12abc34(ef)", 2) // => []string{"12","(ef)"}
sl = re.Split(" abc!", -1) // => []string{" ","!"}
sl = re.Split("123 456", -1) // => []string{"123 456"}
Cet exercice porte sur l'analyse de fichiers de logs.
À la suite d'un récent audit de sécurité, on t'a demandé de nettoyer les fichiers de logs archivés de l'organisation.
Toutes les strings passées aux fonctions sont garanties non nulles et sans espaces au début ni à la fin.
Tu as besoin de te faire une idée du nombre de lignes de log de ton archive qui ne respectent pas les normes actuelles. Tu penses qu'un test simple permet de savoir si une ligne de log est valide. Pour être considérée comme valide, une ligne doit commencer par l'une des strings suivantes :
Implémente la fonction IsValidLine pour qu'elle renvoie false si une string n'est pas valide, et true sinon.
IsValidLine("[ERR] A good error here")
// => true
IsValidLine("Any old [ERR] text")
// => false
IsValidLine("[BOB] Any old text")
// => false
Une nouvelle équipe a rejoint l'organisation, et tu découvres que ses fichiers de logs utilisent un séparateur étrange pour les « champs ». Au lieu de quelque chose de raisonnable comme le deux-points « : », ils utilisent une string telle que « <---> » ou « <=> » (parce que c'est plus joli), en fait n'importe quelle string dont le premier caractère est « < », dont le dernier caractère est « > » et qui contient, entre les deux, n'importe quelle combinaison des caractères « ~ », « * », « = » et « - ».
Implémente la fonction SplitLogLine qui prend une ligne et renvoie un tableau de chaînes de caractères contenant chacune un champ.
SplitLogLine("section 1<*>section 2<~~~>section 3")
// => []string{"section 1", "section 2", "section 3"},
password dans du texte entre guillemetsL'équipe a besoin de connaître les références aux mots de passe dans le texte entre guillemets afin qu'elles puissent être examinées manuellement.
Implémente la fonction CountQuotedPasswords pour donner une idée de l'ampleur probable du travail manuel.
Identifie les lignes de log où la string « password », qui peut être écrite dans n'importe quelle combinaison de majuscules et de minuscules, est entourée de guillemets. Tu dois tenir compte de la possibilité qu'il y ait du contenu supplémentaire entre les guillemets, avant et après « password ». Chaque ligne contient au plus deux guillemets.
Les lignes passées à la routine peuvent être valides ou non au sens de la tâche 1. On les traite de la même façon, qu'elles soient valides ou non.
lines := []string{
`[INF] passWord`, // contains 'password' but not surrounded by quotation marks
`"passWord"`, // count this one
`[INF] User saw error message "Unexpected Error" on page load.`, // does not contain 'password'
`[INF] The message "Please reset your password" was ignored by the user`, // count this one
}
// => 2
Tu as découvert qu'un traitement des logs en amont sème un peu partout le texte « end-of-line » suivi d'un numéro de ligne (sans espace entre les deux).
Implémente la fonction RemoveEndOfLineText qui prend une string, en supprime le texte de fin de ligne et renvoie une string « propre ».
Les lignes qui ne contiennent pas de texte de fin de ligne doivent être renvoyées sans modification.
Supprime uniquement la string de fin de ligne. N'essaie pas d'ajuster les espaces.
RemoveEndOfLineText("[INF] end-of-line23033 Network Failure end-of-line27")
// => "[INF] Network Failure "
Tu as remarqué que certaines lignes de log contiennent des phrases qui font référence à des utilisateurs.
Ces phrases contiennent toujours la string "User", suivie d'un ou plusieurs espaces, puis d'un nom d'utilisateur.
Tu décides d'étiqueter ces lignes.
Implémente une fonction TagWithUserName qui traite les lignes de log :
"User " restent inchangées."User ", préfixe la ligne par [USR] suivi du nom d'utilisateur.Par exemple :
result := TagWithUserName([]string{
"[WRN] User James123 has exceeded storage space.",
"[WRN] Host down. User Michelle4 lost connection.",
"[INF] Users can login again after 23:00.",
"[DBG] We need to check that user names are at least 6 chars long.",
})
// => []string {
// "[USR] James123 [WRN] User James123 has exceeded storage space.",
// "[USR] Michelle4 [WRN] Host down. User Michelle4 lost connection.",
// "[INF] Users can login again after 23:00.",
// "[DBG] We need to check that user names are at least 6 chars long."
// }
Tu peux supposer que :
"User " apparaît au plus une fois par ligne.Inscris-toi sur Exercism pour apprendre et maîtriser Go avec 34 concepts165 exercices, et un vrai mentorat humain, le tout gratuitement.