Есть ли стандарт хранения нормализованных телефонных номеров в базе данных?

95

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

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

where dbo.f_normalizenum(num1) = dbo.f_normalizenum(num2)

что ужасно неэффективно. Кроме того, запросы, которые ищут такие вещи, как код города, становятся чрезвычайно сложными, когда это всего лишь одно поле varchar.

[Редактировать]

Здесь много хороших предложений, спасибо! В качестве обновления вот что я делаю сейчас: я все еще храню числа в том виде, в котором они были введены, в поле varchar, но вместо нормализации вещей во время запроса у меня есть триггер, который выполняет все, что работает при вставке записей или обновлено. Итак, у меня есть целые числа или большие значения для любых частей, которые мне нужно запросить, и эти поля индексируются, чтобы запросы выполнялись быстрее.

Эрик Зи Берд
источник
Современный ответ на вопрос здесь - stackoverflow.com/a/51761170/968003 . Суть этого - использовать RFC 3966 для хранения и libphonenumber для синтаксического анализа / проверки.
Alex Klaus

Ответы:

80

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

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

  • C Код страны 1-10 цифр (сейчас 4 или меньше, но это может измениться)
  • Код города (провинция / штат / регион) код 0-10 цифр (на самом деле может потребоваться, чтобы поле региона и поле области раздельно, а не один код города)
  • E Обменный код (префикс или переключатель) 0-10 цифр
  • L Номер строки 1-10 цифр

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

Кроме того, внутри каждой страны существуют разные стандарты. Вы всегда можете рассчитывать на (AAA) EEE-LLLL в США, но в другой стране у вас могут быть телефонные станции в городах (AAA) EE-LLL и просто номера линий в сельской местности (AAA) LLLL. Вам нужно будет начать с вершины дерева некоторой формы и отформатировать их по мере того, как у вас есть информация. Например, код страны 0 имеет известный формат для остальной части номера, но для кода страны 5432 вам может потребоваться изучить код города, прежде чем вы поймете остальную часть номера.

Вы также можете обрабатывать vanityчисла, такие как (800) Lucky-Guy, что требует признания того, что, если это номер в США, там слишком много цифр (и вам может потребоваться полное представление для рекламы или других целей) и что в США буквы сопоставляются с номера иначе, чем в Германии.

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

Адам Дэвис
источник
1
Знаете ли вы о какой-либо хорошей проверке JavaScript, чтобы попытаться проверить это?
cmcculloh
6
E164 устанавливает гораздо более строгие ограничения на длину номеров: 1-3 для стран и максимальную длину 15. Это не изменится в ближайшее время, зная о глобальной системе телефонии.
Rich
В соответствии с ITU-T E.164 указанные вами длины кажутся совершенно неправильными. Было бы полезно, если бы вы могли разместить ссылку на документ стандартов, из которого вы получаете свою информацию, или объяснить, почему E.164 не применяется.
Abtin Forouzandeh
5
@Abtin - не все телефонные системы соответствуют ITU-T E.164. Однако подавляющее большинство из них это делает, и стоит взвесить выбор между соответствием стандартам и блокировкой некоторых людей или выходом за рамки того, что говорится в стандарте, и принятием всех. Обратите внимание, что E.164 можно рассматривать как подмножество вышеприведенной схемы. Тем не менее, я считаю, что лучший формат - это то, что пользователь ввел точно, а затем алгоритм синтаксического анализа, при необходимости, токенизирует его, а не хранит токенизированную форму в базе данных.
Адам Дэвис
1) Можно ли предположить, что все международные номера соответствуют наличию компонентов CAE? 2) Можете ли вы предположить, что компонент C - единственное, что отличается в зависимости от того, откуда вы набираете номер. Например, номер 850-555-1234 в США имеет A = 850 и E = 555-1234, а затем C = 1 при наборе из США и C = 001 при наборе из Великобритании. Дело в том, что независимо от того, откуда вы набираете номер, A и E никоим образом не являются динамическими, верно?
AaronLS
55

KISS - Я устаю от многих американских веб-сайтов. У них есть грамотно написанный код для проверки почтовых индексов и номеров телефонов. Когда я ввожу свою совершенно действительную норвежскую контактную информацию, я обнаруживаю, что довольно часто она отклоняется.

Оставьте строку, если вам не нужно что-то более сложное.

Бьорн Реппен
источник
Старая добрая версия nvarchar(42)с небольшой проверкой /^+?[0-9 -\.\(\)#*]{4,41}$/работает очень хорошо!
SandRock
Я согласен, но в то же время не согласен. Обычно вы хотите что-то сделать с этим сохраненным номером телефона, например, отобразить его. Вместо того, чтобы идти по этому пути, пытаясь проанализировать его достаточно, чтобы отобразить его так, как вы хотите, я бы предпочел сохранить его в нормализованном виде. Я не говорю, что мы должны заходить так далеко, чтобы ограничить код города скобками. Я говорю, что это все числа без тире и т. Д.
The Muffin Man
4
Я считаю, что телефонные номера следует анализировать перед их сохранением, чтобы их можно было проверить и сохранить в нормализованном виде. Международный синтаксический анализ и форматирование телефонных номеров вполне возможно с googlei18n / libphonenumber .
Роэл
21

Страница Википедии о E.164 должна рассказать вам все, что вам нужно знать.

Богатый
источник
3
нет, этот стандарт просто определяет структуру телефонных номеров (они состоят из трех номеров), но не определяет, как они должны отображаться и / или храниться. Я сказал стандартный? Я имел ввиду Рекомендацию .
BlueWizard
8

Вот моя предлагаемая структура, буду благодарен за отзывы:

Поле базы данных телефонов должно быть varchar (42) в следующем формате:

CountryCode - номер x добавочный номер

Так, например, в США мы могли бы иметь:

1-2125551234x1234

Это будет представлять собой номер в США (код страны 1) с кодом / номером зоны (212) 555 1234 и добавочным номером 1234.

Разделение кода страны тире делает код страны понятным для тех, кто просматривает данные. Это не является строго необходимым, поскольку коды стран являются « кодами префиксов » (вы можете читать их слева направо, и вы всегда сможете однозначно определить страну). Но, поскольку коды стран имеют разную длину (на данный момент от 1 до 4 символов), вы не можете легко определить код страны, если не используете какой-либо разделитель.

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

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

Почему я выбрал varchar (42)? Во-первых, международные телефонные номера будут иметь разную длину, отсюда и слово «вар». Я храню тире и «x», так что это объясняет «char», и в любом случае вы не будете выполнять целочисленные арифметические операции с телефонными номерами (я полагаю), поэтому нет смысла пытаться использовать числовой тип . Что касается длины 42, я использовал максимально возможную длину всех суммированных полей, основываясь на ответе Адама Дэвиса, и добавил 2 для тире и «x».

непреднамеренно оставлено пустым
источник
7

Найдите E.164. Обычно вы храните номер телефона в виде кода, начинающегося с префикса страны и необязательного суффикса PBX. Тогда дисплей - это проблема локализации. Проверка также может выполняться, но это также проблема локализации (на основе префикса страны).

Например, + 12125551212 + 202 будет отформатирован в локали en_US как (212) 555-1212 x202. У него был бы другой формат в en_GBили de_DE.

Информации о ITU-T E.164 довольно много, но она довольно загадочная.

Jcoby
источник
6

Мне лично нравится идея хранения нормализованного телефонного номера varchar (например, 9991234567), а затем, конечно же, форматирования этого телефонного номера в строке при его отображении.

Таким образом, все данные в вашей базе данных будут «чистыми» и без форматирования.

Майк Филден
источник
4

Место хранения

Храните телефоны в RFC 3966 (например +1-202-555-0252, +1-202-555-7166;ext=22). Основное отличие от E.164 :

  • Нет ограничений по длине
  • Поддержка расширений

Чтобы оптимизировать производительность операций просмотра, сохраните телефон в национальном / международном формате рядом с полем RFC 3966.

Не храните код страны в отдельном поле, если у вас нет для этого серьезной причины. Зачем? Потому что вы не должны запрашивать код страны в пользовательском интерфейсе.

В основном люди входят в телефоны, когда их слышат. Например, если локальный формат будет начинаться с 0или 8, пользователю будет неприятно выполнять преобразование чисел в заголовке (например, « Хорошо, не вводите« 0 », выберите страну и введите остальную часть того, что человек сказал в этой области ").

Парсинг

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

Так что пусть пользователь просто вводит " 0449053501" или " 04 4905 3501" или " (04) 4905 3501". Все остальное инструмент сделает за вас.

Посмотрите официальную демонстрацию , чтобы понять, насколько это помогает.

Алекс Клаус
источник
3

Возможно, сохранение разделов телефонных номеров в разных столбцах, позволяющих вводить пустые или пустые записи?

Томас Оуэнс
источник
3

Итак, исходя из информации на этой странице, вот начало валидатора международных телефонных номеров:

function validatePhone(phoneNumber) {
    var valid = true;
    var stripped = phoneNumber.replace(/[\(\)\.\-\ \+\x]/g, '');    

    if(phoneNumber == ""){
        valid = false;
    }else if (isNaN(parseInt(stripped))) {
        valid = false;
    }else if (stripped.length > 40) {
        valid = false;
    }
    return valid;
}

Примерно на основе сценария с этой страницы: http://www.webcheatsheet.com/javascript/form_validation.php

оборота смcculloh
источник
2

Стандарт форматирования чисел - e.164. Вы всегда должны хранить числа в этом формате. Никогда не разрешайте добавочный номер в одно поле с номером телефона, они должны храниться отдельно. Что касается числовых и буквенно-цифровых, это зависит от того, что вы собираетесь делать с этими данными.

Брайан Уэст
источник
1

Я думаю, что свободный текст (возможно, varchar (25)) - наиболее широко используемый стандарт. Это позволит использовать любой формат, как внутренний, так и международный.

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

Дон
источник
Это упускает из виду суть вопроса, которая заключается в стандартизации содержимого полей БД для обеспечения уникального соответствия. Как мне убедиться, что когда я запрашиваю номер телефона 800-555-1212, он соответствует, если пользователь может ввести "(800) 555-1212", "+1.800.555.1212" или любое другое эквивалентное значение? Это решаемая проблема.
Irongaze.com
1

Я считаю, что большинство веб-форм правильно позволяют ввести код страны, код города, а затем оставшиеся 7 цифр, но почти всегда забывают разрешить ввод расширения. Это почти всегда приводит к тому, что я говорю гневные слова, так как на работе у нас нет портье, и мне нужен внутренний номер.

Аарон
источник
1

Я считаю, что большинство веб-форм правильно позволяют ввести код страны, код города, а затем оставшиеся 7 цифр, но почти всегда забывают разрешить ввод расширения. Это почти всегда приводит к тому, что я говорю гневные слова, так как на работе у нас нет портье, и мне нужен внутренний номер.

Мне бы пришлось проверить, но я думаю, что наша схема БД похожа. У нас есть код страны (по умолчанию он может быть США, не уверен), код города, 7 цифр и добавочный номер.

Томас Оуэнс
источник
1

Как насчет сохранения столбца с произвольным текстом, который показывает удобную для пользователя версию телефонного номера, а затем нормализованную версию, в которой удаляются пробелы, скобки и расширяется '+'. Например:

Удобный:Удобно +44 (0) 181 4642542

Нормализованный: 00441814642542

ColinYounger
источник
10
Для кого именно +44 (0) 181 4642542 предназначен для дружеских отношений? Пользователи из Великобритании, которые могут не знать, что делать с +44, если они не привыкли звонить за границу, или пользователи из других стран, которые не знают, что они должны отказаться от (0)?
Марк Бейкер
0

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


источник
0

Откуда у вас телефонные номера? Если вы получаете их из части телефонной сети, вы получите строку цифр, а также тип номера и план, например

441234567890 тип / план 0x11 (что означает международный E.164)

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

Марк Бейкер
источник
0

Удобный для пользователя: +44 (0) 181464 2542 нормализованный: 00441814642542

(0) недействителен в международном формате. См. Стандарт ITU-T E.123.

«Нормализованный» формат бесполезен для читателей из США, поскольку они используют 011 для международного доступа.

Дэйв певец
источник
0

Я использовал 3 разных способа хранения телефонных номеров в зависимости от требований использования.

  1. Если номер хранится только для поиска человеком и не будет использоваться для поиска, он хранится в поле строкового типа точно так, как его ввел пользователь.
  2. Если в поле будет выполняться поиск, любые лишние символы, такие как +, пробелы, скобки и т. Д., Удаляются, а оставшееся число сохраняется в поле строкового типа.
  3. Наконец, если номер телефона будет использоваться приложением компьютера / телефона, то в этом случае его нужно будет ввести и сохранить как действительный номер телефона, который может использовать система, этот вариант, конечно, сложнее всего кодировать. для.
Jimoc
источник