Комплексное регулярное выражение для проверки номера телефона - PullRequest
874 голосов
/ 24 сентября 2008

Я пытаюсь составить подробное регулярное выражение для проверки телефонных номеров. В идеале он должен обрабатывать международные форматы, но он должен обрабатывать американские форматы, включая следующие:

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

Я отвечу своей текущей попыткой, но я надеюсь, что у кого-то есть что-то лучше и / или более элегантно.

Ответы [ 39 ]

502 голосов
/ 24 сентября 2008

Лучший вариант ... просто уберите все нецифровые символы на входе (кроме «х» и начальных «+» знаков), соблюдая осторожность из-за британской тенденции писать цифры в нестандартной форме попросили использовать международный префикс (в этом конкретном случае вы должны полностью отказаться от (0)).

Затем вы получите такие значения, как:

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

Затем, когда вы отобразите, переформатируйте содержание вашего сердца. например, * +1008 *

  1 (234) 567-8901
  1 (234) 567-8901 x1234
290 голосов
/ 24 сентября 2008

Оказывается, что-то вроде спецификации для этого, по крайней мере для Северной Америки, называется NANP .

Вам нужно указать именно то, что вы хотите. Что такое юридические разделители? Пробелы, тире и периоды? Разделитель не допускается? Можно ли смешивать разделители (например, + 0,111-222,3333)? Как будут обрабатываться расширения (например, 111-222-3333 x 44444)? А как насчет специальных номеров, таких как 911? Код города будет необязательным или обязательным?

Вот регулярное выражение для 7- или 10-значного числа с разрешенными расширениями, разделителями являются пробелы, тире или точки:

^(?:(?:\+?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+))?$
286 голосов
/ 07 августа 2009
.*

Если пользователь хочет дать вам свой номер телефона, то доверяйте ему, чтобы он правильно понял. Если он не хочет давать его вам, то принуждение его ввести действительное число либо отправит его на сайт конкурента, либо заставит ввести случайную строку, соответствующую вашему регулярному выражению. У меня даже может возникнуть желание посмотреть номер секс-линии премиум-класса и ввести ее вместо этого.

Я бы также рассмотрел любое из следующих действий в качестве допустимых записей на веб-сайте:

"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"
153 голосов
/ 26 марта 2013

Я бы также посоветовал взглянуть на " libphonenumber " в библиотеке Google. Я знаю, что это не регулярное выражение, но он делает именно то, что вы хотите.

Например, он распознает, что:

15555555555

- возможный номер, но не действительный номер. Он также поддерживает страны за пределами США.

Основные функциональные возможности:

  • Разбор / форматирование / проверка телефонных номеров для всех стран / регионов мира.
  • getNumberType - получает тип номера на основе самого номера; возможность различать фиксированные, мобильные, бесплатные, премиальные, общие, VoIP и персональные номера (когда это возможно).
  • isNumberMatch - получает уровень достоверности того, могут ли два числа совпадать.
  • getExampleNumber / getExampleNumberByType - предоставляет действительные номера примеров для всех стран / регионов с возможностью указания, какой тип примера номера телефона требуется.
  • isPossibleNumber - быстро угадать, является ли номер возможным телефонным номером, используя только информацию о длине, намного быстрее, чем полная проверка.
  • isValidNumber - полная проверка номера телефона для региона с использованием информации о длине и префиксе.
  • AsYouTypeFormatter - форматирование телефонных номеров на лету, когда пользователи вводят каждую цифру.
  • findNumbers - находит цифры при вводе текста.
  • PhoneNumberOfflineGeocoder - предоставляет географическую информацию, связанную с номером телефона.

Примеры

Самая большая проблема с проверкой номера телефона - это очень культурная зависимость.

  • America
    • (408) 974–2042 является действительным номером США
    • (999) 974–2042 является недействительным номер США
  • Австралия
    • 0404 999 999 является действительным австралийским номером
    • (02) 9999 9999 также является действительным австралийским номером
    • (09) 9999 9999 является недействительным австралийский номер

Регулярное выражение отлично подходит для проверки формата телефонного номера, но на самом деле не удастся проверить достоверность телефонного номера.

Я бы предложил пропустить простое регулярное выражение для проверки вашего телефонного номера и использовать библиотеку, такую ​​как Google libphonenumber (ссылка на проект GitHub) .

Представляем libphonenumber!

Используя один из ваших более сложных примеров, 1-234-567-8901 x1234, вы получаете следующие данные из libphonenumber (ссылка на онлайн-демонстрацию) :

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

Таким образом, вы не только узнаете, является ли номер телефона действительным (каким он является), но также вы получаете согласованное форматирование номера телефона в вашем регионе.

В качестве бонуса, libphonenumber имеет ряд наборов данных для проверки правильности телефонных номеров, поэтому проверяется такой номер, как +61299999999 (международная версия (02) 9999 9999). возвращается как действительное число с форматированием:

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 также дает вам много дополнительных преимуществ, таких как захват местоположения, в котором обнаружен номер телефона, а также получение информации о часовом поясе с номера телефона:

PhoneNumberOfflineGeocoder Results
Location        Australia

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

Но недействительный австралийский номер телефона ((09) 9999 9999) показывает, что это недопустимый номер телефона.

Validation Results

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

В версии Google есть код для Java и Javascript, но люди также внедрили библиотеки для других языков, которые используют набор телефонных номеров Google i18n:

Если вы не уверены, что вы всегда будете принимать числа из одной локали, и они всегда будут в одном формате, я настоятельно рекомендую не писать свой собственный код для этого и использовать libphonenumber для проверки и отображения номера телефонов.

72 голосов
/ 07 января 2014

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

Это соответствует:

 - (+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

На $ n экономит:

  1. Индикатор страны
  2. Номер телефона
  3. Extension

Вы можете проверить это на https://www.regexpal.com/?fam=99127

63 голосов
/ 24 сентября 2008

Хотя ответ на удаление всех пробелов является аккуратным, на самом деле он не решает поставленную задачу - найти регулярное выражение. Взять, к примеру, мой тестовый скрипт, который загружает веб-страницу и извлекает все номера телефонов с помощью регулярных выражений. Так как вам все равно понадобится регулярное выражение, вы можете также сделать так, чтобы регулярное выражение выполняло всю работу. Я придумал это:

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

Вот скрипт на Perl для его проверки. Когда вы совпадаете, $ 1 содержит код города, $ 2 и $ 3 - номер телефона, а $ 5 - добавочный номер. Мой тестовый скрипт загружает файл из Интернета и печатает все номера телефонов в нем.

#!/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";
        }
}

Edit:

Вы можете изменить \ W * на \ s * \ W? \ S * в регулярном выражении, чтобы немного его сжать. Я не думал о регулярном выражении с точки зрения, скажем, проверки пользовательского ввода в форме, когда писал его, но это изменение позволяет использовать регулярное выражение для этой цели.

'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*))?';
40 голосов
/ 14 августа 2014

Я ответил на этот вопрос на другом вопросе SO, прежде чем решил также включить свой ответ в качестве ответа в этой теме, потому что никто не обращался к тому, как требовать / не требовать элементы, просто раздавая регулярные выражения: Regex работает неправильно, сопоставляя неожиданные вещи

Из моего поста на этом сайте я создал краткое руководство, чтобы помочь любому с созданием собственного регулярного выражения для своего желаемого формата телефонного номера, который я предостерегаю (как я делал на другом сайте), что если вы Излишне ограниченный, вы можете не получить желаемых результатов, и не существует единого решения для всех возможных телефонных номеров в мире - только то, что вы решите принять в качестве предпочтительного формата. Используйте на свой страх и риск.

Быстрый шпаргалка

  • Запустите выражение: /^
  • Если вам требуется пробел, используйте: [\s] или \s
  • Если вы хотите использовать скобки, используйте: [(] и [)]. Использование \( и \) ужасно и может привести к путанице.
  • Если вы хотите, чтобы что-то было необязательным, поставьте ? после него
  • Если вы хотите использовать дефис, просто наберите - или [-]. Если вы не ставите его первым или последним в ряду других персонажей, вам, возможно, придется его убрать: \-
  • Если вы хотите принять разные варианты в слоте, заключите их в квадратные скобки: [-.\s] потребуется дефис, точка или пробел. Знак вопроса после последней скобки сделает все эти поля необязательными для этого слота.
  • \d{3}: Требуется трехзначное число: 000-999. Сокращение для [0-9][0-9][0-9].
  • [2-9]: для этого слота требуется цифра 2-9.
  • (\+|1\s)?: Примите «плюс» или 1 и пробел (символ трубы, |, «или») и сделайте его необязательным. Знак «плюс» должен быть экранирован.
  • Если вы хотите, чтобы определенные числа соответствовали слоту, введите их: [246] потребует 2, 4 или 6. [77|78] потребуется 77 или 78.
  • $/: конец выражения
28 голосов
/ 04 февраля 2010

Я написал проще всего (хотя мне не нужна точка в нем).

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

Как упомянуто ниже, он проверяет только символы, а не его структуру / порядок

22 голосов
/ 21 марта 2010

Обратите внимание, что зачистка () символов не работает для стиля записи британских номеров, который является общим: +44 (0) 1234 567890, что означает набор либо международного номера:
+441234567890
или в Великобритании наберите 01234567890

21 голосов
/ 16 августа 2012

Если вы просто хотите убедиться, что у вас нет случайного мусора в поле (т. Е. От спамеров форм), это регулярное выражение должно работать хорошо:

^[0-9+\(\)#\.\s\/ext-]+$

Обратите внимание, что в нем нет специальных правил относительно количества цифр или чисел, допустимых в этих цифрах, просто проверяется, что только цифры, скобки, тире, плюс, пробел, фунт, звездочка, точка, запятая, или буквы e, x, t присутствуют.

Должно быть совместимо с международными номерами и форматами локализации. Предвидите ли вы необходимость разрешать квадратные, фигурные или угловые скобки для некоторых регионов? (в настоящее время они не включены).

Если вы хотите сохранить правила для каждой цифры (например, коды США и префиксы (коды обмена) должны находиться в диапазоне 200-999), удачи вам. Поддерживать сложный набор правил, который может быть устаревшим в любой момент в будущем любой страной в мире, не кажется забавным.

И хотя удаление всех / большинства нечисловых символов может хорошо работать на стороне сервера (особенно, если вы планируете передавать эти значения в номеронабиратель), вы можете не захотеть сбрасывать ввод пользователя во время проверки, особенно если вы хотите, чтобы они внесли исправления в другом поле.

...