L’expression régulière pour laquelle je reçois le plus de retours, sans parler des rapports de « bug », est celle que vous trouverez juste sur la page d’accueil de ce site : \b+@+\.{2,}\b. Cette expression régulière, selon moi, correspond à n’importe quelle adresse électronique. La plupart des réactions que je reçois réfutent cette affirmation en montrant une adresse électronique à laquelle cette expression régulière ne correspond pas. Généralement, le rapport de « bug » comprend également une suggestion pour rendre la regex « parfaite ».
Comme je l’explique ci-dessous, mon affirmation ne tient que si l’on accepte ma définition de ce qu’est réellement une adresse électronique valide, et de ce qu’elle n’est pas. Si vous voulez utiliser une définition différente, vous devrez adapter le regex. Faire correspondre une adresse email valide est un exemple parfait montrant que (1) avant d’écrire une regex, vous devez savoir exactement ce que vous essayez de faire correspondre, et ce que vous ne voulez pas ; et (2) il y a souvent un compromis entre ce qui est exact, et ce qui est pratique.
La vertu de mon expression régulière ci-dessus est qu’elle correspond à 99% des adresses email utilisées aujourd’hui. Toutes les adresses électroniques qu’elle fait correspondre peuvent être traitées par 99 % de tous les logiciels de messagerie qui existent. Si vous cherchez une solution rapide, il vous suffit de lire le paragraphe suivant. Si vous voulez connaître tous les compromis et obtenir de nombreuses alternatives parmi lesquelles choisir, lisez la suite.
Si vous voulez utiliser l’expression régulière ci-dessus, il y a deux choses que vous devez comprendre. Premièrement, les longues regex rendent difficile la mise en forme agréable des paragraphes. Je n’ai donc pas inclus a-z dans l’une des trois classes de caractères. Cette regex est destinée à être utilisée avec l’option « insensible à la casse » de votre moteur de regex activée. (Vous seriez surpris du nombre de rapports de « bogue » que je reçois à ce sujet.) Deuxièmement, la regex ci-dessus est délimitée par des frontières de mots, ce qui la rend appropriée pour extraire des adresses électroniques de fichiers ou de blocs de texte plus importants. Si vous voulez vérifier si l’utilisateur a tapé une adresse électronique valide, remplacez les limites des mots par des ancres de début de chaîne et de fin de chaîne, comme ceci : ^+@+\.{2,}$.
Le paragraphe précédent s’applique également à tous les exemples suivants. Vous devrez peut-être changer les limites des mots en ancres de début et de fin de chaîne, ou vice versa. Et vous devez activer l’option de correspondance insensible à la casse.
Les compromis dans la validation des adresses électroniques
Avant que l’ICANN ne permette à toute entreprise bien financée de créer ses propres domaines de premier niveau, les domaines de premier niveau les plus longs étaient les .museum et .travel, rarement utilisés, qui comptent 6 lettres. Les domaines de premier niveau les plus courants comportaient 2 lettres pour les domaines spécifiques à un pays, et 3 ou 4 lettres pour les domaines généraux comme .com et .info. Un grand nombre de regex pour la validation des adresses électroniques que vous trouverez dans divers tutoriels et références sur les regex supposent toujours que le domaine de premier niveau est assez court. Les anciennes éditions de ce tutoriel sur les regex mentionnaient \b+@+\.{2,4}\b comme regex pour les adresses électroniques dans son introduction. Il n’y a qu’une seule petite différence entre cette expression et celle qui figure en haut de cette page. Le 4 à la fin de la regex limite le domaine de premier niveau à 4 caractères. Si vous utilisez cette expression avec des ancres pour valider l’adresse électronique saisie dans votre formulaire de commande, [email protected] doit faire ses achats ailleurs. Oui, le TLD .solutions existe et au moment où j’écris ces lignes, disaproved.solutions peut être à vous pour 16,88 $ par an.
Si vous voulez être plus strict que {2,} pour le domaine de premier niveau, ^+@+\.{2,63}$ est le plus loin que vous puissiez pratiquement aller. Chaque partie d’un nom de domaine ne peut dépasser 63 caractères. Il n’existe aucun domaine de premier niveau à un seul chiffre et aucun ne contient de chiffres. Il ne semble pas que l’ICANN approuvera de tels domaines non plus.
Les adresses électroniques peuvent être sur des serveurs dans un sous-domaine comme dans [email protected]. Toutes les regex ci-dessus correspondent à cette adresse électronique, car j’ai inclus un point dans la classe de caractères après le symbole @. Mais les regex ci-dessus correspondent également à john@aol…com, qui n’est pas valide en raison des points consécutifs. Vous pouvez exclure ces correspondances en remplaçant +\. par (?:+\.)+ dans l’une des regex ci-dessus. J’ai supprimé le point de la classe de caractères et répété à la place la classe de caractères et le point littéral suivant. Par exemple, ^+@(?:+\.)+{2,}$ correspond à [email protected] mais pas à john@aol…com.
Si vous voulez éviter que votre système s’étouffe sur une entrée arbitrairement grande, vous pouvez remplacer les quantificateurs infinis par des quantificateurs finis. ^{1,64}@(?:{1,63}\.){1,125}{2,63}$ tient compte du fait que la partie locale (avant le @) est limitée à 64 caractères et que chaque partie du nom de domaine est limitée à 63 caractères. Il n’y a pas de limite directe au nombre de sous-domaines. Mais la longueur maximale d’une adresse électronique pouvant être traitée par SMTP est de 254 caractères. Donc, avec une partie locale à un seul caractère, un domaine de premier niveau à deux lettres et des sous-domaines à un seul caractère, 125 est le nombre maximal de sous-domaines.
La regex précédente ne limite pas réellement les adresses électroniques à 254 caractères. Si chaque partie est à sa longueur maximale, la regex peut correspondre à des chaînes de caractères d’une longueur maximale de 8129 caractères. Vous pouvez réduire cette longueur en diminuant le nombre de sous-domaines autorisés de 125 à quelque chose de plus réaliste comme 8. Je n’ai jamais vu une adresse électronique avec plus de 4 sous-domaines. Si vous voulez faire respecter la limite de 254 caractères, la meilleure solution est de vérifier la longueur de la chaîne d’entrée avant même d’utiliser une regex. Bien que cela nécessite quelques lignes de code procédural, la vérification de la longueur d’une chaîne est quasi instantanée. Si vous ne pouvez utiliser que des regex, ^{6,254}$ peut être utilisé comme première passe pour s’assurer que la chaîne ne contient pas de caractères invalides et n’est ni trop courte ni trop longue. Si vous devez tout faire avec une seule regex, vous aurez besoin d’une regex qui supporte le lookahead. L’expression régulière ^(?={6,254}$){1,64}@(?:{1,63}\.){1,8}{2,63}$ utilise un lookahead pour vérifier d’abord que la chaîne ne contient pas de caractères non valides et n’est ni trop courte ni trop longue. Lorsque le lookahead réussit, le reste de la regex effectue un deuxième passage sur la chaîne pour vérifier le bon placement du signe @ et des points.
Toutes ces regex autorisent les caractères ._%+- n’importe où dans la partie locale. Vous pouvez forcer la partie locale à commencer par une lettre en utilisant ^{0,63} au lieu de ^{1,64} pour la partie locale : ^{0,63}@(?:{1,63}\.){1,125}{2,63}$. Lorsque l’on utilise le lookahead pour vérifier la longueur totale de l’adresse, le premier caractère peut être vérifié dans le lookahead. Nous n’avons pas besoin de répéter la vérification du caractère initial lorsque nous vérifions la longueur de la partie locale. Cette regex est trop longue pour s’adapter à la largeur de la page, alors activons le mode espacement libre :
^(?={5,253}$)
{1,64}@(?:{1,63}\.){1,8}{2,63}$
Les noms de domaine peuvent contenir des tirets. Mais ils ne peuvent pas commencer ou se terminer par un trait d’union. (?:{0,62}) ? correspond à un nom de domaine de 1 à 63 caractères qui commence et se termine par une lettre ou un chiffre. Le groupe de non-capture rend le milieu du domaine et la lettre ou le chiffre final facultatifs dans leur ensemble afin de s’assurer que nous autorisons les domaines à un seul caractère tout en garantissant que les domaines à deux caractères ou plus ne se terminent pas par un trait d’union. La regex globale commence à devenir assez compliquée :
^{0,63}@
(? :(?:{0,62})?\.){1,8}{2,63}$
Les noms de domaine ne peuvent pas contenir de tirets consécutifs. +(?:-+)* correspond à un nom de domaine qui commence et se termine par une lettre ou un chiffre et qui contient un nombre quelconque de traits d’union non consécutifs. C’est la méthode la plus efficace. Cette regex ne fait pas de retour en arrière pour trouver un nom de domaine valide. Elle correspond à toutes les lettres et à tous les chiffres au début du nom de domaine. S’il n’y a pas de trait d’union, le groupe optionnel qui suit échoue immédiatement. S’il y a des traits d’union, le groupe correspond à chaque trait d’union suivi de toutes les lettres et chiffres jusqu’au trait d’union suivant ou jusqu’à la fin du nom de domaine. Nous ne pouvons pas imposer la longueur maximale lorsque les traits d’union doivent être associés à une lettre ou à un chiffre, mais les lettres et les chiffres peuvent se suffire à eux-mêmes. Mais nous pouvons utiliser la technique du lookahead que nous avons utilisée pour faire respecter la longueur totale de l’adresse électronique afin de faire respecter la longueur du nom de domaine tout en interdisant les traits d’union consécutifs : (?={1,63}\.)+(?:-+)*. Notez que le lookahead vérifie également le point qui doit apparaître après le nom de domaine lorsqu’il est entièrement qualifié dans une adresse électronique. Ce point est important. Sans la vérification du point, la tête de recherche accepterait des noms de domaine plus longs. Étant donné que la tête de lecture ne consomme pas le texte qu’elle correspond, le point n’est pas inclus dans la correspondance globale de cette expression rationnelle. Lorsque nous mettons cette regex dans la regex globale pour les adresses électroniques, le point sera mis en correspondance comme il l’était dans les regex précédentes :
^{0,63}@
(? :(?={1,63}\.)+(?:-+)*\.){1,8}{2,63}$
Si nous incluons le lookahead pour vérifier la longueur globale, notre regex fait deux passages sur la partie locale, et trois passages sur les noms de domaine pour tout valider:
^( ?={5,253}$){1,64}@
(? :(?={1,63}\.)+(?:-+)*\.){1,8}{2,63}$
Sur un PC ou un serveur moderne, cette regex fonctionnera très bien lors de la validation d’une seule adresse électronique de 254 caractères. Le rejet d’une entrée plus longue serait même plus rapide car la regex échouera lorsque le lookahead échouera lors du premier passage. Mais je ne recommanderais pas d’utiliser une regex aussi complexe que celle-ci pour rechercher des adresses électroniques dans une grande archive de documents ou de correspondance. Il est préférable d’utiliser la regex simple en haut de cette page pour rassembler rapidement tout ce qui ressemble à une adresse électronique. Dédoublez les résultats, puis utilisez une regex plus stricte si vous voulez filtrer davantage les adresses invalides.
Et en parlant de retour en arrière, aucune des regex de cette page ne fait de retour en arrière pour correspondre à des adresses électroniques valides. Mais particulièrement les dernières peuvent faire un backtracking assez important sur quelque chose qui n’est pas tout à fait une adresse email valide. Si votre regex supporte les quantificateurs possessifs, vous pouvez éliminer tout retour en arrière en rendant tous les quantificateurs possessifs. Puisqu’aucun retour en arrière n’est nécessaire pour trouver des correspondances, cela ne change pas ce qui est recherché par ces regex. Cela leur permet seulement d’échouer plus rapidement lorsque l’entrée n’est pas une adresse électronique valide. Notre regex la plus simple devient alors ^++@++\.{2,}+$ avec un + supplémentaire après chaque quantificateur. Nous pouvons faire de même avec notre regex la plus complexe :
^(?={5,253}+$){1,64}+@
(? :(?={1,63}+\.)++(?:-++)*+\.){1,8}+{2,63}+$
Un compromis important dans toutes ces regex est qu’elles n’autorisent que les lettres anglaises, les chiffres et les symboles spéciaux les plus couramment utilisés. La raison principale est que je ne fais pas confiance à tous mes logiciels de messagerie pour être en mesure de gérer beaucoup d’autres choses. Même si John.O’[email protected] est une adresse électronique syntaxiquement valide, il y a un risque que certains logiciels interprètent mal l’apostrophe comme un guillemet de délimitation. Insérer aveuglément cette adresse électronique dans une requête SQL, par exemple, la fera au mieux échouer lorsque les chaînes sont délimitées par des guillemets simples et, au pire, ouvrira votre site aux attaques par injection SQL.
Et bien sûr, cela fait déjà plusieurs années que les noms de domaine peuvent inclure des caractères non anglais. Mais la plupart des logiciels s’en tiennent toujours aux 37 caractères auxquels les programmeurs occidentaux sont habitués. La prise en charge des domaines internationalisés ouvre toute une boîte de Pandore sur la manière dont les caractères non ASCII doivent être encodés. Ainsi, si vous utilisez l’une des regex de cette page, toute personne ayant une adresse @ทีเอชนิค.ไทย n’aura pas de chance. Mais il est peut-être révélateur que http://ทีเอชนิค.ไทย redirige simplement vers http://thnic.co.th, même si leur activité consiste à vendre des domaines .ไทย.
La conclusion est que pour décider de l’expression régulière à utiliser, que vous essayiez de faire correspondre une adresse électronique ou autre chose de vaguement défini, vous devez commencer par envisager tous les compromis. Est-il mauvais de faire correspondre quelque chose qui n’est pas valide ? Quel est l’inconvénient de ne pas faire correspondre quelque chose qui est valide ? Quelle peut être la complexité de votre expression régulière ? Quel serait le coût d’une modification ultérieure de l’expression régulière parce qu’elle s’est avérée trop large ou trop étroite ? Des réponses différentes à ces questions nécessiteront une expression régulière différente comme solution. Ma regex d’email fait ce que je veux, mais il se peut qu’elle ne fasse pas ce que vous voulez.
Les regex n’envoient pas d’email
N’allez pas trop loin en essayant d’éliminer les adresses email invalides avec votre expression régulière. La raison est que vous ne savez pas vraiment si une adresse est valide jusqu’à ce que vous essayiez de lui envoyer un email. Et même cela peut ne pas être suffisant. Même si l’e-mail arrive dans une boîte aux lettres, cela ne signifie pas que quelqu’un lit encore cette boîte aux lettres. Si vous voulez vraiment être sûr qu’une adresse électronique est valide, vous devez lui envoyer un message contenant un code ou un lien permettant au destinataire d’effectuer une deuxième étape d’authentification. Et si vous faites cela, alors il n’y a guère d’intérêt à utiliser une regex qui pourrait rejeter des adresses électroniques valides.
Le même principe s’applique dans de nombreuses situations. Lorsque vous essayez de faire correspondre une date valide, il est souvent plus facile d’utiliser un peu d’arithmétique pour vérifier les années bissextiles, plutôt que d’essayer de le faire dans une regex. Utilisez une expression régulière pour trouver des correspondances potentielles ou vérifier si l’entrée utilise la bonne syntaxe, et effectuez la validation réelle sur les correspondances potentielles renvoyées par l’expression régulière. Les expressions régulières sont un outil puissant, mais elles sont loin d’être une panacée.
La norme officielle : RFC 5322
Vous vous demandez peut-être pourquoi il n’existe pas d’expression régulière « officielle » infaillible pour faire correspondre les adresses électroniques. Eh bien, il existe une définition officielle, mais elle est difficilement infaillible.
La norme officielle est connue sous le nom de RFC 5322. Elle décrit la syntaxe à laquelle doivent se conformer les adresses électroniques valides. Vous pouvez (mais vous ne devriez pas – lisez la suite) l’implémenter avec l’expression régulière suivante. La RFC 5322 laisse la partie relative au nom de domaine ouverte à des choix d’implémentation spécifiques qui ne fonctionneront pas sur Internet aujourd’hui. L’expression régulière met en œuvre la syntaxe » préférée » de la RFC 1035 qui est l’une des recommandations de la RFC 5322 :
\A(?:+(?:\.+)*
| « (?:
| \\\)* »)
@ (? :(?:(?:*) ?\.)+(?:*) ?
| \|2| ??)\.){3}
(?:25|2|??|*:
(?:
| \\\)+)
\])\z
Cette regex a deux parties : la partie avant le @, et la partie après le @. Il existe deux alternatives pour la partie avant le @. La première alternative lui permet de se composer d’une série de lettres, de chiffres et de certains symboles, y compris un ou plusieurs points. Toutefois, les points ne peuvent pas apparaître consécutivement ou au début ou à la fin de l’adresse électronique. L’autre solution exige que la partie précédant le @ soit placée entre guillemets, ce qui permet d’insérer n’importe quelle chaîne de caractères ASCII entre les guillemets. Les caractères d’espacement, les guillemets doubles et les barres obliques inversées doivent être échappés avec des barres obliques inversées.
La partie après le @ a également deux alternatives. Il peut s’agir soit d’un nom de domaine pleinement qualifié (par exemple, regular-expressions.info), soit d’une adresse Internet littérale entre crochets. L’adresse Internet littérale peut être soit une adresse IP, soit une adresse de routage spécifique au domaine.
La raison pour laquelle vous ne devriez pas utiliser cette regex est qu’elle est trop large. Votre application peut ne pas être en mesure de gérer toutes les adresses électroniques que cette regex autorise. Les adresses de routage spécifiques à un domaine peuvent contenir des caractères de contrôle ASCII non imprimables, ce qui peut poser problème si votre application doit afficher des adresses. Toutes les applications ne prennent pas en charge la syntaxe de la partie locale utilisant des guillemets doubles ou des crochets. En fait, le RFC 5322 lui-même marque la notation utilisant des crochets comme obsolète.
Nous obtenons une mise en œuvre plus pratique du RFC 5322 si nous omettons les adresses IP, les adresses spécifiques à un domaine, la syntaxe utilisant les doubles guillemets et les crochets. Elle correspondra toujours à 99,99 % de toutes les adresses électroniques réellement utilisées aujourd’hui.
\A+(?:\.+)*@
(? :(?:*)?\.)+(?:*)?\z
Aucune de ces regex n’applique de limites de longueur à l’adresse électronique globale ou à la partie locale ou aux noms de domaine. La RFC 5322 ne spécifie aucune limite de longueur. Celles-ci proviennent de limitations dans d’autres protocoles comme le protocole SMTP pour l’envoi effectif d’e-mails. La RFC 1035 stipule que les domaines doivent comporter 63 caractères ou moins, mais ne l’inclut pas dans sa spécification syntaxique. La raison en est qu’un véritable langage régulier ne peut pas à la fois imposer une limite de longueur et interdire les traits d’union consécutifs. Mais les saveurs modernes de regex ne sont pas vraiment régulières, donc nous pouvons ajouter des vérifications de limite de longueur en utilisant lookahead comme nous le faisions auparavant :
\A(?={6,254}\z)
(?={1,64}@)
+( ?:\.+)*
@ (? :(?={1,63}\.)(?:*)?\.)+
(?={1,63}\z)(?:*)?\z
Donc, même en suivant les normes officielles, il reste des compromis à faire. Ne copiez pas aveuglément des expressions régulières provenant de bibliothèques en ligne ou de forums de discussion. Testez-les toujours sur vos propres données et avec vos propres applications.
Faire un don
Ce site vient-il de vous épargner un voyage en librairie ? Faites un don pour soutenir ce site et vous obtiendrez un accès à vie à ce site sans publicité !
.