IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Regex pour email.


Sujet :

Langage PHP

  1. #1
    Membre régulier
    Homme Profil pro
    Apprenti perpétuel
    Inscrit en
    Novembre 2012
    Messages
    194
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Apprenti perpétuel

    Informations forums :
    Inscription : Novembre 2012
    Messages : 194
    Points : 72
    Points
    72
    Par défaut Regex pour email.
    Bonjour,

    Voici quelques regex en php pour email que j'ai trouvé sur le net. Qu'en pensez-vous?

    /^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix
    /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/
    /[a-z0-9_\-\+\.]+@[a-z0-9\-]+\.([a-z]{2,4})(?:\.[a-z]{2})?/i
    /([a-z0-9_\.\-])+\@(([a-z0-9\-])+\.)+([a-z0-9]{2,4})+/i
    /^w+[+.w-]*@([w-]+.)*w+[w-]*.([a-z]{2,4}|d+)$/i

    Dans le cadre d'un bot qui collecterait des emails ecrits dans un document,
    j'ai pondu ma propre regex que j'ai voulu la plus simple possible:
    ~[\S]+@[\S]+\.[\S]+~m

    Qu'en pensez-vous?

    Au fait, laquelle des fonctions php suivantes est la mieux pour lire une variable?
    "fopen() + fread() + fclose()" ou "readfile()" ou "file_get_contents()"

    Merci à: https://geekflare.com/regular-expression-tester/
    Merci aussi à ce petit site génial pour tester les regex: https://regex101.com/

  2. #2
    Expert éminent sénior
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 394
    Points : 15 755
    Points
    15 755
    Par défaut
    j'ai aussi trouvé cette expression régulière qui s'approche plus de la RFC
    https://www.vmr-globalsolutions.eu/i...c-822_673.html

    il y a aussi cette fonction qui refuse juste les adresses "abc@localhost" alors qu'elles sont valides :
    https://www.php.net/manual/fr/function.filter-var.php
    vous pouvez aussi utiliser cette fonction pour savoir si le domaine a un serveur MX :
    https://www.php.net/manual/fr/function.getmxrr.php

  3. #3
    Membre régulier
    Homme Profil pro
    Apprenti perpétuel
    Inscrit en
    Novembre 2012
    Messages
    194
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Apprenti perpétuel

    Informations forums :
    Inscription : Novembre 2012
    Messages : 194
    Points : 72
    Points
    72
    Par défaut
    Merci mathieu,

    Euh oui..., mais l'idée n'est pas de faire la regex la plus longue possible mais la plus courte possible.
    La mienne marche très bien sauf si il n'y a pas d'espace entre l'email et une quelconque balise html lors de la lecture d'un document html par mon le bot que j'ai réalisé.

    Quel terme ajouteriez vous dans ma regex pour éviter la prise en compte par preg_match_all() d'une éventuelle balise html qui serait coller en bordure de l'email?

  4. #4
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 896
    Points : 6 655
    Points
    6 655
    Par défaut
    Citation Envoyé par olivierdauxais Voir le message
    Bonjour,

    Voici quelques regex en php pour email que j'ai trouvé sur le net. Qu'en pensez-vous?

    /^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix
    /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/
    /[a-z0-9_\-\+\.]+@[a-z0-9\-]+\.([a-z]{2,4})(?:\.[a-z]{2})?/i
    /([a-z0-9_\.\-])+\@(([a-z0-9\-])+\.)+([a-z0-9]{2,4})+/i
    /^\w+[+.\w-]*@([\w-]+\.)*\w+[\w-]*\.([a-z]{2,4}|\d+)$/i (avec les antislashes qui ont sauté)
    Ces 5 patterns ont été écrites dans le but de valider une adresse email (avec plus ou moins de bonheur) mais pas de trouver une adresse email qui serait à l'intérieur d'une chaîne contenant d'autres choses. Il s'agit peu ou prou de la même pattern avec plus ou moins d'éléments délirants à l'intérieur suivant les versions, mais toutes ont vocation à décrire une adresse du type jean.dubois@trucmuche.fr et rien d'autre de plus olé olé.
    Il est inutile de chercher à faire les deux choses à la fois (trouver et valider). Donc effectivement la meilleur chose à faire est de composer une pattern qui peut récupérer les sous-chaînes succeptibles d'être des adresses email. Le filtrage des adresses invalides se fera dans un deuxième temps avec filter_var($email, FILTER_VALIDATE_EMAIL) (qui n'est certes pas parfait mais qu'on peut améliorer avec quelques traitements au préalable sur les lettres non-ascii).

    Dans le cadre d'un bot qui collecterait des emails ecrits dans un document,
    j'ai pondu ma propre regex que j'ai voulu la plus simple possible:
    ~[\S]+@[\S]+\.[\S]+~m
    L'approche est bonne, une fois débarrassée de ce qui ne sert pas, ça donne ~\S+@\S+\.\S+~, mais:
    • tu n'auras pas les emails dont la partie local contient des espaces: "huguette\ blanchard"@votez.pour.moi
    • tu n'auras pas non plus les emails dont le domaine est une ipv6: postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]
    • comme tu l'as constaté, il est difficile de démarrer ou de s'arrêter au bonne endroit avec une pattern trop permissive: n'hésitez pas à me contacter par email (jean.benoit@bidule.com), ou par téléphone.
    • bien que simple, ce n'est pas une pattern trés efficace:
      • elle sera testée plus avant (au delà du premier caractère) à chaque position où se trouve un caractère non blanc.
      • comme \S contient également le caractère @, elle provoquera du backtracking pour que \S+@ puisse réussir, même chose pour \S+\.


    Je ne te blâme pas, c'est loin d'être simple.

    Ce que tu peux tenter:
    • charger les pages html avec DOMDocument::loadHTMLFile, obtenir tous les nœuds texte avec DOMXPath::query et la requête suivante //text(), ça te débarrasera du problème des balises html et la pattern sera testée sur des chaînes moins grandes.
    • utiliser une pattern dans ce goût là:
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      $pattern = <<<'REGEX'
      ~ 
      (?=["\w!#$%&'*+/=?^`{|}\~-])
      (?: [\w!#$%&'*+/=?^`{|}\~-] [^\s@"\\]* (*SKIP) @
        | " [^\v"\\]*+ (?:\\ [^\v] [^\v"\\]* )*+ " @
      )
      (?: [\p{Xan}-]+ (?: \. [\p{Xan}-]+ )*
        | \[ (?: [0-9.]+ ] | IPv6: [a-f0-9:]+ ] )
      )
      ~ixu
      REGEX;
      Elle est plus complexe mais elle devrait résoudre le problème de départ et d'arrêt en limitant les caractères possible au début et à la fin. De plus, elle est assez performante:
      • la première ligne avec le test avant (?=["\w!#$%&'*+/=?^`{|}\~-]) permet d'évacuer toutes les positions ne commençant pas par un des caractères de la classe sans avoir à tester le groupe qui suit.
      • [\w!#$%&'*+/=?^`{|}\~-] [^\s@"\\]* (*SKIP) @ avec le (*SKIP) permet de sauter directement à la position déjà atteinte en cas d'absence du @.
      • le backtracking est quasi inexistant.

      Elle supporte les parties locales entre double quotes et les adresses internationalisées. (le modificateur u étend la classe \w aux chiffres et lettres de tous les alphabets, \p{Xan} désigne les chiffres et lettres de tous les alphabets mais ne contient pas le _ qui est interdit dans le nom de domaine)


    regex101 est trés pratique, par contre cette page contient pas mal d'âneries et d'imprécisions en tous genres, et il est clair que toutes les "recettes" de pattern c'est du copier/coller (les groupes, les échappements, les classes qui ne servent à rien ne trompent pas). Donc mieux vaut y regarder à deux fois, construire ses patterns soi-même et se référer aux sources (comme pcre.org pour le moteur de regex de PHP, et le livre de Jeffrey Friedl).

  5. #5
    Membre régulier
    Homme Profil pro
    Apprenti perpétuel
    Inscrit en
    Novembre 2012
    Messages
    194
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Apprenti perpétuel

    Informations forums :
    Inscription : Novembre 2012
    Messages : 194
    Points : 72
    Points
    72
    Par défaut
    Merci CosmoKnacki, tu m'as appris plein de trucs.

    Je ne savais pas que la partie locale d'une adresse email pouvait contenir un ou plusieurs espaces.
    Je ne connaissais pas non plus le coup des adresses avec une ipv6.
    Statistiquement, ces 2 possibilités sont plutôt rare. N'est-ce pas?
    Je cherche surtout à trouver les adresses emails classiques de personnes chez yahoo ou gmail... etc...

    Je ne savais pas non plus qu'un nom de domaine ne peut contenir de "_". C'est bon à savoir.
    Les extensions de domaine ne sont uniquement que des lettres minuscules. N'est-ce pas?

    Je vais appliquer ta suggestion de faire en 2 étapes:
    1- Trouver les adresses emails parmi un texte avec ma petite regex.
    2- Les valider avec la fonction intégrée php: filter_var($email, FILTER_VALIDATE_EMAIL)

    Concernant ma regex, j'ai donc laissé tomber ma regex: ~[\S]+@[\S]+\.[\S]+~m
    que tu as simplifié encore mieux, en effet, comme suit: ~\S+@\S+\.\S+~m

    J'ai ensuite créé cette regex qui marche mieux: ~[a-z0-9_\-\.]+@[a-z0-9_\-\.]+\.[a-z]+~mi
    Mais, si j'ai bien compris ce que tu dis: \w est l'équivalent de a-z0-9_ N'est-ce pas?
    Du coup je pourrais donc réduire encore plus ma regex ci dessus comme suit:
    ~[\w\-\.]+@[\w\-]+\.[a-z]+~mi
    N'est ce pas?

    Certaines adresses emails comme celles contenant des espaces ne seront pas trouvés...
    Sauf si j'y ajoute \s comme suit: ~[\w\-\.\s]+@[\w\-]+\.[a-z]+~mi
    N'est-ce pas?

    Mais oups... Cette regex permet à preg_match_all de sélectionner l'adresse "g @g.g"...
    Est-ce vraiment possible qu'il puisse exister des adresses emails avec un espace avant le @?

    Tu trouveras ci-dessous mon petit bout de code test html qui contient des adresses emails:

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    <!DOCTYPE html><html><head><meta charset="UTF-8"> <title>Test</title></head>
    <body><p>1st line: A@a.a or Bb@bb.bb<br />
    3rd email:<br />cc3@cc3.ccc </p>
    <p>d-d@d-d.ddd <br /> e.e@eee.eee<br />f f_f@fff.fff</p>
    <p>g @g.g or g@ g.g or g@g .g or g@g. g or g @ g . g End</p>
    </body></html>

  6. #6
    Membre régulier
    Homme Profil pro
    Apprenti perpétuel
    Inscrit en
    Novembre 2012
    Messages
    194
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Apprenti perpétuel

    Informations forums :
    Inscription : Novembre 2012
    Messages : 194
    Points : 72
    Points
    72
    Par défaut
    Re-bonjour CosmoKnacki,

    Après réflexion, maintenant que j'utilise cette regex:
    ~[a-z0-9_\-\.]+@[a-z0-9_\-\.]+\.[a-z]+~mi
    ou celle-ci: ~[\w\-\.]+@[\w\-]+\.[a-z]+~mi
    Je risque certes de ne pas trouver toutes les adresses email qui se trouveraient dans un texte
    mais je ne risque pas d'en trouver qui ne soit pas valide. N'est-ce pas?
    Dés lors, nul besoin d'utiliser FILTER_VALIDATE_EMAIL qui fera doublon. N'est-ce pas?

    Fidèlement à ma manie de toujours vouloir écrire les codes les plus courts...
    Nobody is perfect... Je suis un minimaliste... Mais comme dirait St Exupéry:
    "La perfection est atteinte non quand il ne reste rien à ajouter mais lorsqu'il ne reste rien à enlever."
    Ce qui tendrait à positionner le minimalisme comme la perfection absolue...

  7. #7
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 896
    Points : 6 655
    Points
    6 655
    Par défaut
    Oui bien entendu ces adresses avec des syntaxes particulières (partie locale entre quotes, nom de domaine sous forme d'IP) sont plus rares du fait notamment d'un manque de support certains serveurs d'emails et des validations de formulaire, il en va de même pour celles qui comportent des accents ou utilisent d'autres alphabets.
    Et non, FILTER_VALIDATE_EMAIL ne fera pas doublon. Quelques recherches sur la syntaxe des adresses email te le confirmeront.
    Les espaces dans la partie locale ne sont possibles qu'entre quotes.
    Le point ne s'échappe pas dans une classe de caractères et on peut éviter d'échapper le tiret en le plaçant au début ou à la fin de la classe. Le modificateur m ne sert à rien.

    "La perfection est atteinte non quand il ne reste rien à ajouter mais lorsqu'il ne reste rien à enlever."
    Ce qui tendrait à positionner le minimalisme comme la perfection absolue.
    Encore faut-il savoir ce qui peut être enlevé; tu peux commencer par la pensée magique.

    À ta place je ne renoncerais pas aux caractères !#$%&'*+/=?^`{|}\~, ni au (*SKIP) d'ailleurs qui évite de repasser sur des positions inutiles.
    Quelques soient tes choix, fait des tests réalistes, prend une page html de bonne taille, colle une adresse email à la fin et regarde le nombre de steps nécessaires sur regex101 ou mesure le temps dans un script.

  8. #8
    Membre régulier
    Homme Profil pro
    Apprenti perpétuel
    Inscrit en
    Novembre 2012
    Messages
    194
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Apprenti perpétuel

    Informations forums :
    Inscription : Novembre 2012
    Messages : 194
    Points : 72
    Points
    72
    Par défaut
    Oui CosmoKnacki, comme tu dis: "Encore faut-il savoir ce qui peut être enlevé."
    Et c'est bien là mon problème et c'est pourquoi je prends conseil sur ce forum.

    Décembre 2018, j'avais fait 2 petites regex: ~^www~m et ~http\S*~
    pour activer les liens postés sur un mini forum avec preg_replace.
    Mais, je n'ai pas eu l'occasion d'en refaire depuis et j'ai tout oublié.
    Par exemple, je ne me souviens même plus de l'utilité de * dans ma regex ci-dessus que j'ai pourtant concocté moi-même.

    Excuses moi, CosmoKnacki, de ne pas avoir encore adopté ta regex sur laquelle tu as passé du temps à l'élaborer.
    Ta regex m'impressionne et je ne comprends pas chacun de ces caractères.
    Je n'aime pas utiliser quelques chose dont je ne comprends pas chacun de ses éléments.
    Et les explications officielles des divers éléments manquent bien souvent de pédagogie...

    A propos, je réalise que \w est l'équivalent de: a-zA-Z0-9_ et non de: a-z0-9_ N'est-ce pas?
    Et oups, j'ai oublié \. dans la 2ème partie de ma regex bis:
    ~[\w\-\.]+@[\w\-]+\.[a-z]+~mi
    Et puisque le m et le i devienne inutile, cela pourrait devenir:
    ~[\w\-\.]+@[\w\-\.]+\.[a-z]+~
    N'est ce pas? Je n'ai pas trop compris tes explications sur les échappements du - et du .
    Comment transformerais-tu ma regex ci-dessus pour tenir compte de ta suggestion sur ces échappements?

    Cette notion de backtracking est intéressante pour la performance.
    C'est quelque chose auquel je n'avais pas pensé.
    Bien noté aussi que le modulateur m est inutile. Merci.

Discussions similaires

  1. Réponses: 1
    Dernier message: 24/02/2011, 14h41
  2. Utilisation de Regex pour regrouper des emails
    Par NicoNGRI dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 18/02/2008, 16h51
  3. composant delphi 7 pour email
    Par jupierre dans le forum Composants VCL
    Réponses: 2
    Dernier message: 22/08/2006, 10h16
  4. [RegEx] Regex pour les accents et autres
    Par yule dans le forum Langage
    Réponses: 4
    Dernier message: 21/08/2006, 15h47
  5. regexp pour email
    Par noinneh dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 28/12/2004, 11h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo