Regex mention @nomdutilisateur GitHub
L'auteur de la question de référence sur Stack Overflow voulait repérer les mentions « @pseudo » dans un paragraphe pour les relier à leur profil GitHub. Sa propre regex, publiée dans la question, a un vrai défaut qu'il constate lui-même : elle ne reconnaît pas les pseudos à un seul caractère comme « @a ». Notre analyse ReDoS révèle un second problème, plus grave : elle est vulnérable (complexité polynomiale), vérifié sur une chaîne de simples « @ » répétés. Le même défaut de conception (un lookahead qui scrute tout le reste du texte au lieu de se limiter au pseudo courant) fait aussi échouer un pseudo pourtant valide dès qu'un double tiret apparaît plus loin dans le texte. Une réponse à 4 votes corrige le bug du pseudo à 1 caractère mais hérite du second défaut. Une autre tentative, tirée d'un commentaire évoquant de vrais comptes GitHub « historiques » aux règles plus permissives (comme github.com/artur-), accepte volontairement des formes que les règles actuelles interdisent. Voici un motif sûr qui corrige ces défauts, comparé à ces 3 tentatives réelles.
/\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))/iComparatif des patterns existants
| Source | pattern | Score sur le corpus | ReDoS |
|---|---|---|---|
| Stack Overflow — regex de l'auteur de la question, ne reconnaît pas les pseudos à 1 caractère (bug constaté dans la question elle-même) et scrute tout le reste du texte pour un double tiret | \B@((?!.*(-){2,}.*)[a-z0-9][a-z0-9-]{0,38}[a-z0-9]) | 17 / 20 | vulnérable (@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@…) |
| Stack Overflow — motif suggéré en commentaire pour couvrir de vrais comptes historiques aux règles plus permissives, accepte tirets/underscores en tête ou en fin (contraire aux règles actuelles) | \B@[a-z0-9_-]{1,39} | 17 / 20 | sûr |
| Stack Overflow — réponse à 4 votes, corrige le bug du pseudo à 1 caractère mais hérite du même lookahead scrutant tout le reste du texte | \B@(?!.*(-){2,}.*)[a-z0-9](?:[a-z0-9-]{0,37}[a-z0-9])?\b | 18 / 20 | indéterminé |
Implémentation
const re = new RegExp("\\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))", "i");
re.test(input);Limites
- Reflète les règles de nommage ACTUELLES de GitHub, pas l'historique complet : un commentaire sur le fil source signale l'existence de vrais comptes plus anciens (comme github.com/artur-) conservés tels quels malgré des règles depuis durcies — un tel identifiant historique serait rejeté par ce motif.
- S'arrête au premier caractère invalide plutôt que de rejeter tout le token : sur « @ignore-last-dash- », il reconnaît « @ignore-last-dash » en ignorant le tiret final, un choix de conception hérité du fil source (comportement demandé explicitement par l'auteur de la question), pas une validation stricte de bout en bout.
- Ne vérifie pas que le nom d'utilisateur correspond à un compte GitHub réellement existant : seule la forme est vérifiée, pas l'inscription réelle sur la plateforme.
- Le « \B » qui précède le « @ » distingue une mention d'une adresse e-mail dans la plupart des cas courants, mais reste une heuristique : un texte inhabituel (ponctuation collée sans espace avant un « @ » de mention) peut théoriquement dérouter cette distinction.