Question Une regex complète pour la validation du numéro de téléphone


J'essaie de mettre en place une regex complète pour valider les numéros de téléphone. Idéalement, il traiterait les formats internationaux, mais il doit gérer les formats américains, notamment:

  • 1-234-567-8901
  • 1-234-567-8901 x1234
  • 1-234-567-8901 ext1234
  • 1 (234) 567-8901
  • 1.234.567.8901
  • 1/234/567/8901
  • 12345678901

Je vais répondre avec ma tentative actuelle, mais j'espère que quelqu'un a quelque chose de mieux et / ou plus élégant.


824


origine


Réponses:


Meilleure option ... il suffit de supprimer tous les caractères non numériques en entrée (sauf les signes 'x' et '+'), en prenant soin de la tendance britannique à écrire des nombres sous la forme non standard +44 (0) ... lorsqu'on vous demande d'utiliser le préfixe international (dans ce cas précis, vous devez rejeter le (0) entièrement).

Ensuite, vous vous retrouvez avec des valeurs comme:

 12345678901
 12345678901x1234
 345678901x1234
 12344678901
 12345678901
 12345678901
 12345678901
 +4112345678
 +441234567890

Ensuite, lorsque vous affichez, reformatez le contenu de votre cœur. par exemple.

  1 (234) 567-8901
  1 (234) 567-8901 x1234

482



Il se trouve qu'il y a quelque chose d'une spécification pour cela, au moins pour l'Amérique du Nord, appelé le PNNA.

Vous devez spécifier exactement ce que vous voulez. Quels sont les délimiteurs légaux? Espaces, tirets et périodes? Aucun délimiteur autorisé? Peut-on mélanger des délimiteurs (par exemple, + 0.111-222.3333)? Comment les extensions (par exemple, 111-222-3333 x 44444) vont-elles être gérées? Qu'en est-il des numéros spéciaux, comme le 911? L'indicatif régional sera-t-il facultatif ou requis?

Voici une regex pour un nombre à 7 ou 10 chiffres, avec les extensions autorisées, les délimiteurs sont des espaces, des tirets ou des points:

^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$

277



.*

Si l'utilisateur veut vous donner son numéro de téléphone, alors faites-lui confiance pour le faire correctement. S'il ne veut pas vous le donner, le forcer à entrer un numéro valide l'enverra sur le site d'un concurrent ou lui fera entrer une chaîne aléatoire qui correspond à votre regex. Je pourrais même être tenté de rechercher le numéro d'une ligne de sexe à taux majoré et d'entrer cela à la place.

Je considérerais également l'un des éléments suivants comme des entrées valides sur un site Web:

"123 456 7890 until 6pm, then 098 765 4321"  
"123 456 7890 or try my mobile on 098 765 4321"  
"ex-directory - mind your own business"

274



Je suggère également de regarder le "libphonenumber"Google Library, je sais que ce n'est pas regex mais il fait exactement ce que vous voulez.

Par exemple, il reconnaîtra que:

15555555555

est un nombre possible mais pas un nombre valide. Il soutient également des pays en dehors des États-Unis.

Faits saillants de la fonctionnalité:

  • Analyser / formater / valider les numéros de téléphone pour tous les pays / régions du monde.
  • getNumberType - obtient le type du nombre basé sur le nombre lui-même; capable de distinguer les numéros fixes, mobiles, sans frais, les tarifs préférentiels, les coûts partagés, la VoIP et les numéros personnels (lorsque cela est possible).
  • isNumberMatch - obtient un niveau de confiance pour savoir si deux nombres pourraient être identiques.
  • getExampleNumber/getExampleNumberByType - fournit des exemples de numéros valides pour tous les pays / régions, avec la possibilité de spécifier le type de numéro de téléphone requis.
  • isPossibleNumber - deviner rapidement si un nombre est un numéro de téléphone possible en utilisant seulement l'information de longueur, beaucoup plus rapidement qu'une validation complète.
  • isValidNumber - validation complète d'un numéro de téléphone pour une région en utilisant les informations de longueur et de préfixe.
  • AsYouTypeFormatter- formate les numéros de téléphone à la volée lorsque les utilisateurs entrent chaque chiffre.
  • findNumbers - trouve des nombres dans la saisie de texte.
  • PhoneNumberOfflineGeocoder - fournit des informations géographiques relatives à un numéro de téléphone.

Exemples

Le plus gros problème avec la validation du numéro de téléphone est qu'il est très dépendant de la culture.

  • Amérique
    • (408) 974–2042 est un valide Numéro américain
    • (999) 974–2042 est pas valide Numéro américain
  • Australie
    • 0404 999 999 est un valide Numéro australien
    • (02) 9999 9999 est aussi un valide Numéro australien
    • (09) 9999 9999 est pas valide Numéro australien

Une expression régulière est très bien pour vérifier le format d'un numéro de téléphone, mais il ne sera pas vraiment en mesure de vérifier le validité d'un numéro de téléphone.

Je suggère de sauter une expression régulière simple pour tester votre numéro de téléphone contre, et en utilisant une bibliothèque comme celle de Google libphonenumber (lien vers le projet GitHub).

Présentation de libphonenumber!

En utilisant l'un de vos exemples les plus complexes, 1-234-567-8901 x1234, vous obtenez les données suivantes sur libphonenumber (lien vers la démo en ligne):

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     true

Formatting Results:

E164 format                    +12345678901
Original format                (234) 567-8901 ext. 123
National format                (234) 567-8901 ext. 123
International format           +1 234-567-8901 ext. 123
Out-of-country format from US  1 (234) 567-8901 ext. 123
Out-of-country format from CH  00 1 234-567-8901 ext. 123

Ainsi, non seulement vous apprendrez si le numéro de téléphone est valide (ce qui est le cas), mais vous obtiendrez également un format de numéro de téléphone cohérent dans vos paramètres régionaux.

En prime, libphonenumber a un certain nombre de jeux de données pour vérifier la validité des numéros de téléphone, ainsi, en vérifiant un nombre tel que +61299999999 (la version internationale de (02) 9999 9999) renvoie un nombre valide avec formatage:

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     true

Formatting Results

E164 format                    +61299999999
Original format                61 2 9999 9999
National format                (02) 9999 9999
International format           +61 2 9999 9999
Out-of-country format from US  011 61 2 9999 9999
Out-of-country format from CH  00 61 2 9999 9999

libphonenumber vous donne également de nombreux avantages supplémentaires, tels que saisir l'emplacement où le numéro de téléphone est détecté, et obtenir également les informations de fuseau horaire à partir du numéro de téléphone:

PhoneNumberOfflineGeocoder Results
Location        Australia

PhoneNumberToTimeZonesMapper Results
Time zone(s)    [Australia/Sydney]

Mais le numéro de téléphone australien invalide ((09) 9999 9999) renvoie que ce n'est pas un numéro de téléphone valide.

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     false

La version de Google a un code pour Java et Javascript, mais les gens ont également implémenté des bibliothèques pour d'autres langues qui utilisent l'ensemble de données de numéros de téléphone Google i18n:

À moins que vous ne soyez certain que vous accepterez toujours des numéros d'un lieu et qu'ils seront toujours dans un format, je vous suggère fortement de ne pas écrire votre propre code et d'utiliser libphonenumber pour valider et afficher les numéros de téléphone.


128



/^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$/i

Cela correspond à:

 - (+351) 282 43 50 50
 - 90191919908
 - 555-8909
 - 001 6867684
 - 001 6867684x1
 - 1 (234) 567-8901
 - 1-234-567-8901 x1234
 - 1-234-567-8901 ext1234
 - 1-234 567.89/01 ext.1234
 - 1(234)5678901x1234
 - (123)8575973
 - (0055)(123)8575973

Sur $ n, cela économise:

  1. Indicateur de pays
  2. Numéro de téléphone
  3. Extension

Vous pouvez le tester sur https://www.regexpal.com/?fam=99127


65



Bien que la réponse à la suppression de tous les espaces soit nette, elle ne résout pas vraiment le problème posé, qui est de trouver une regex. Prenez, par exemple, mon script de test qui télécharge une page Web et extrait tous les numéros de téléphone en utilisant la regex. Puisque vous auriez besoin d'une regex de toute façon, vous pourriez aussi bien avoir l'expression régulière faire tout le travail. Je suis venu avec ça:

1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?

Voici un script Perl pour le tester. Lorsque vous faites correspondre, $ 1 contient l'indicatif régional, $ 2 et $ 3 contiennent le numéro de téléphone, et $ 5 contient l'extension. Mon script de test télécharge un fichier depuis Internet et imprime tous les numéros de téléphone.

#!/usr/bin/perl

my $us_phone_regex =
        '1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?';


my @tests =
(
"1-234-567-8901",
"1-234-567-8901 x1234",
"1-234-567-8901 ext1234",
"1 (234) 567-8901",
"1.234.567.8901",
"1/234/567/8901",
"12345678901",
"not a phone number"
);

foreach my $num (@tests)
{
        if( $num =~ m/$us_phone_regex/ )
        {
                print "match [$1-$2-$3]\n" if not defined $4;
                print "match [$1-$2-$3 $5]\n" if defined $4;
        }
        else
        {
                print "no match [$num]\n";
        }
}

#
# Extract all phone numbers from an arbitrary file.
#
my $external_filename =
        'http://web.textfiles.com/ezines/PHREAKSANDGEEKS/PnG-spring05.txt';
my @external_file = `curl $external_filename`;
foreach my $line (@external_file)
{
        if( $line =~ m/$us_phone_regex/ )
        {
                print "match $1 $2 $3\n";
        }
}

Modifier:

Vous pouvez changer \ W * en \ s * \ W? \ S * dans l'expression rationnelle pour le resserrer un peu. Je ne pensais pas à la regex en termes, disons, de validation de l'entrée de l'utilisateur sur un formulaire lorsque je l'ai écrit, mais cette modification permet d'utiliser l'expression régulière à cette fin.

'1?\s*\W?\s*([2-9][0-8][0-9])\s*\W?\s*([2-9][0-9]{2})\s*\W?\s*([0-9]{4})(\se?x?t?(\d*))?';

62



J'ai répondu à cette question sur une autre question de SO avant de décider d'inclure aussi ma réponse comme réponse sur ce sujet, parce que personne ne demandait comment exiger / ne pas exiger des items, en distribuant juste des regex: Regex fonctionne mal, correspondant à des choses inattendues

De mon article sur ce site, j'ai créé un guide rapide pour aider toute personne à faire sa propre regex pour son propre format de numéro de téléphone, que je vais mettre en garde (comme je l'ai fait sur l'autre site) que si vous êtes trop restrictif, vous n'obtiendrez peut-être pas les résultats escomptés, et il n'y a pas de solution unique pour accepter tous les numéros de téléphone possibles dans le monde - seulement ce que vous décidez d'accepter comme format de votre choix. À utiliser à vos risques et périls.

Feuille de triche rapide

  • Commencez l'expression: /^ 
  • Si vous voulez un espace, utilisez: [\s] ou \s 
  • Si vous souhaitez utiliser une parenthèse, utilisez: [(] et [)] . En utilisant \( et \) est moche et peut rendre les choses confuses.
  • Si vous voulez que quelque chose soit facultatif, mettez un ? après ça
  • Si vous voulez un trait d'union, tapez simplement - ou [-] . Si vous ne le mettez pas en premier ou en dernier dans une série d'autres caractères, vous devrez peut-être y échapper: \-
  • Si vous souhaitez accepter différents choix dans un emplacement, placez des crochets autour des options: [-.\s] nécessitera un trait d'union, une période ou un espace. Un point d'interrogation après la dernière parenthèse rendra tous ceux optionnels pour ce slot.
  • \d{3} : Nécessite un nombre à 3 chiffres: 000-999. Raccourci pour [0-9][0-9][0-9].
  • [2-9] : Nécessite un chiffre 2-9 pour cette fente.
  • (\+|1\s)? : Accepter un "plus" ou un 1 et un espace (caractère de pipe, |, est "ou"), et le rend facultatif. Le signe "plus" doit être échappé.
  • Si vous souhaitez que des numéros spécifiques correspondent à un emplacement, entrez-les: [246] nécessitera un 2, 4 ou 6. [77|78] il faudra 77 ou 78.
  • $/ : Terminez l'expression

38



J'ai écrit le plus simple (même si je n'ai pas besoin de point dedans).

^ ([0-9 \ (\) \ / \ + \ -] *) $

Comme mentionné ci-dessous, il vérifie uniquement les caractères, pas sa structure / commande


27