Как стать автором
Обновить

Комментарии 61

Итоговый нормализованный номер будет выглядеть так: +123456789012
Теперь его можно сохранить в виде строки.

Если убрать +, то можно хранить в виде числа int64, что уменьшит размер и значительно упростит поиск.

Можно просто по граблям походить, зачем читать статью.

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

Для знакового 64-битного целого максимальное число 9,223,372,036,854,775,807 - что даёт максимальную длину "телефонного номера" в 18 цифр (или 19 для беззнакового).

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

А теперь представим, что мы храним корпоративный номер, и компания использует дополнительно две трёхзначные группы: три цифры для департамента/отдела, и ещё три - для конкретного сотрудника (это не значит, конечно, что у них миллион сотрудников, но мне такая схема не кажется невозможной).

И вот мы уже упёрлись в потолок - дальше только добавлять столбцы, или использовать какие-то ещё хаки, чтобы сохранить более длинный номер.

Не говоря уже о том, что номер может состоять не только из цифр:

  • Могут использоваться символы не из кодировки ASCII: например, в Египте для написания номеров зачастую используется арабский шрифт.

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

В статье же указано, что номер 7 и 007 это разные номера с точки зрения телефонной связи. В int64 это будет один номер.

Не вижу проблемы. В статье же указано что предлагается использовать форматирование согласно коду страны. Перед сохранением в базу нули отбросятся, при извлечении - добавятся. Телефонная связь не пострадает.

+7077.... и +7007.... - разные номера, точнее даже разные регионы, ABC-код отличается. А при приведении к bigint ведущие нули отбросятся.

И что? Посмотрите на свой собственный пример. Как отбросятся так и вернутся потом назад, ведь количество цифр в номере - фиксировано и заранее известно.

ведь количество цифр в номере - фиксировано и заранее известно

Кто вам сказал такую глупость?

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

Пруфы в студию.

за исключением пары стран

В большинстве стран

Ну то есть из этого правила уже есть исключения. Ну и зачем оно нужно?

количество цифр в номере - фиксировано и заранее известно.

Это с какого, прастити™, перепугу? Вам это количество цифр само рассказало?

Возьмите номера телефонов в городах Лионе, Зальцбурге и Кракове. Там точно одинаковое количество цифр?

А про цифру "2" в первой позиции в АВС-кодах в РФ Вы знаете? Что с ней будем делать-то?

про цифру "2" в первой позиции в АВС-кодах в РФ Вы знаете

Я не знаю, расскажите?

первая "2" в АВС (коде области) - это местные звонки, всегда подставляется тот регион, в котором находится номер. Например, на номер, который из Москвы звонится как (235) 7-12-54, из условного Нска будем звонить как (49535) 7-12-54 %)

Не знал, спасибо за просвещение!

Можете привести пример, не до конца понятно как должно работать.

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

011 и 11 - это один и тот же номер. Еще раз повторяю, количество цифр в номере фиксированное и заранее известно.

Еще раз повторяю, количество цифр в номере фиксированное и заранее известно.

беглое гугление подсказывает что нет, не фиксированное, куча стран где телефоны разной длины, к примеру Финляндия, 8–10

https://en.wikipedia.org/wiki/List_of_mobile_telephone_prefixes_by_country

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

011 и 11 - это один и тот же номер

О сколько Вам открытий чудных готовит суровая реальность, молодой человек...

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

Но придется играть с масками/логикой для работы с номерами 0123.

Пока спасает, что ведущий ноль/ноли имеют специальное значение

не надо в int. а то начнете велосипеды изобретать для добавочных кодов или номеров с буквами

Номерам с ведущими нолями int не понравится.

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

Ну количество ведущих нулей вы тоже можете сохранять. И скорее всего это всё равно будет компактнее и быстрее.

А просто 1 спереди добавить уже не влезет в инт ?

А зачем? Сколько мегабайт удастся сэкономить на хранении всех номеров всех людей планеты?

А вы все значения всего в виде строк храните ?

Ну типа "чего экономить то, всёж бесконечное"...

Есть толстая разница между преждевременной оптимизацией и "и так сойдет".

Есть толстая разница

Есть ещё ложная дихотомия.

чего экономить то, всёж бесконечное

Ну вот и вопрос: чего вы планируете наэкономить? Если где то рядом в этой же таблице будут поля с ФИО, адресом и прочей информацией.

А вы все значения всего в виде строк храните ?

Положите квантор всеобщности на пол и медленно отойдите ;)

Буквы - лишь мнемоники для лучшего запоминания. В итоге все равно передается цифра. Ни в устаревшем импульсном наборе, ни в dtmf не предусмотрено никаких способов передавать буквы.

Вопрос не в том, как передаётся, а в том, как записывается и вводится пользователем.

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

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

Буквы используются лишь как мнемоническое обозначение номера в рекламных целях

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

Хосспаде, ну что за бред вы несете. Сайт в рекламных целях вообще оформляет дизайнер, а не программист. Там номер, скорее всего, вообще будет вставлен bmp-шечкой нужным "красивым" шрифтом.

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

Огромное количество людей записывает номера буквами

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

Я так и написал:

это от недостатка квалификации и узкого кругозора. Вы, почему-то, решили, что весь мир живёт так, как привыкли жить вы.

Вы там на выходных, похоже, слишком сильно на алкоголь налегаете.

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

За сим откланяюсь, хамоватых чудаков и так вокруг слишком много, чтобы на них ещё и в интернете время тратить..

> Огромное количество людей записывает номера буквами

Пруфы в студию

Я уже 40 лет живу, ни разу не видел чтобы кто-то где-то записывал номер буквами.

Вам бы к окулисту записаться, уважаемый...

Хватит уже, или ещё насыпать? А то мне лень.

За хранения номера телефона как int64 нужно бить металической линейкой по пальцам. Сильно.

Хранить всё надо в том виде, в котором собираешься использовать. Компрессировать при этом в int64, только потому, что большинство номеров туда влезает — та самая premature optimization, об опасности которой много написано.

А одно из базовых применений номера — внезапно, dialing. Dialing чаще всего происходит так: контроллер (компьютер) открывает текстовой канал с коммуникационным устройством (модемом), и отдаёт ему строку вида ATD +123456789012. И ждёт ответа. Получается, юзер вводит строку, мы её конвертируем в число чисто для компрессии, храним в int64, а для набора потом конвертируем обратно в строку. Не лучше ли включить компрессию в опциях СУБД? Если место так важно?

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

ВНЕЗАПНО, в некоторых номерах приходится в стратегических местах добвлять паузы, вроде +18001234567,,,,5,,,,1234.

Байтики экономите?

В терминах PostgreSQL: если вам не надо сравнивать значения (больше/меньше) находить диапазоны, вам нужен TEXT. Быстро находить поможет индекс построенный, например, по регулярке.

Добавлю в копилку, что не все номера можно преобразовать в международный формат (и наоборот), поэтому нельзя просто так убирать 0 или 00 в начале - это может быть частью локального номера. По той же причине нельзя добавлять просто так код страны в начало. Хранить номер как число проблематично: 0770 и 770 - это могут быть разные абоненты.

В некоторых номерах есть DTMF коды, как часть номера или как дополнительный набор (добавочный номер).

p.s. есть страны где длина номера переменная и зависит от кучи вещей, например от оператора связи (и зависимость там не блочная, а бывает индивидуальная) и подвести все номера под один стандарт длины нельзя.

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

Насчёт хранить как есть - ок, а как верифицировать корректность номера? Если у клиента пара миллионов лист контактов, допустим? Не верифицируешь, получишь кучу ошибок в репорте, по каждому клиент будет требовать объяснений.

Гугловская либа уже на этапе ввода номера не тольао может конвертировать в е.164, но и отфильтровать некорректно заданные номера. С мобильного же можно куда угодно дозвониться, а там этот стандарт и работает.

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

В телефонной сети, может их не должно гулять.

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

Дозвониться это как? Роботом? Так звонки на бизнес номера роботами запрещены, насколько я знаю. Ни один клиент за много лет не смог выставить подобное требование по поддержке доп набора в автомате.

Я не про дополнительный набор.

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

Более, я бы себе на телефон такую 'АТС', понимающую дополнение к номеру поставил, если бы все это не зарезали напрочь. Чтобы было 'Вышего номера нет в контактах хозяина, пожалуйста, нажмите 1, если....<список из дюжины пунктов> или наберите шестизначный код доступа, чтобы телефон хозяина сразу зазвонил'.

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

По моему опыту - почти все ivr на самом деле понимают код сразу после подъема трубки, независимо от того, что говорят. Достаточно паузы в пару секунд - и все будет замечательно работать.

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

С записью да, проблема, она нестандартизована, не случайно это экстеншн.

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

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

А вообще бывает много странных штук в планах нумерации. Например, в Аргентине для звонков используется один номер, а для SMS другой.

https://en.wikipedia.org/wiki/Telephone_numbers_in_Argentina

To send an SMS text message to an Argentine cell phone from another country, the 9 used internationally when dialing the number for a voice call (and the 15 used for calls within Argentina) is omitted. For example, if the mobile number in Argentina is (11) 15 1234–5678, a voice call from abroad would be dialled as +54 9 11 1234 5678, but a text message would require +54 11 1234 5678, with +54 9 11 1234 5678 usually being invalid.

Если честно, слишком растянутая статья для мысли "в международном формате без-цифровых символов". Ожидал услышать про особенности номеров -- дополнительные коды, прочие особенности (например, как вы сами и написали, арабские символы в Египетских номерах). Ну а если затронули ещё и UI, можно было упомянуть традицию США записывать телефон буквами (+1 444-LAWYER)

Непонятна проблема, есть код страны и телефон. Пусть пользователи пишут как им удобно, ну отображение номера в зависимости от страны. Храним все равно как regexp_replace(number,'[^0-9]','','gi'). Вопрос только для чего телефон нужен. Если просто для информации как "данные о себе", когда каждый пишет кто во что горазд это одно. Другое если это контактная/ключевая информация и тогда её проверяют подтверждением/смс. При этом как ты решаешь у себя в базе писать так оно и будет. Проект в РФ и КЗ - можно даже код не вписывать и получаем 10 цифр.

проблема начинается в тот момент когда надо проверить на совпадение номера телефонов. И это сложно сделать если нет правил их нормализации

Я как-то решал нечто похожее, если берём международную систему (что и было), то я выделил 3 уровня конечного абонента (неважно насколько номер повторяется, что "абонент" может быть несколькими людьми и т.п. вещи), первый уровень - страна "+7" там или "+1" (без плюса, т.к. он всегда), второй уровень то что мы набираем после страны, который является уникальным в принципе сочетанием. То есть пусть для РФ это будет +79254443210, то "уникальность" тут это 9254443210, то есть изнутри можно набрать и +7925... и 8925... при этом 925... остаётся уникальным. Из стран упомянутых выше я брал за "нормальный" номер то как он пишется со страной. Больше исключений не попадалось, но если бы они были я бы определил чётко правило записи в базу исходя из подхода. Третий уровень - добавочный номер, то есть когда по основному номеру трубку сняли и требуется "донабрать" цифры. Такое кстати и у сотовых встречалось.

Совпадение как правило по ключу номер-страна. Номер это стринг с тргм, страна смолинт (в такой именно последовательности). Как правило мы попадаем с точностью до человека/конкретной компании более 99% - цифра от головы, потому что она больше: я чуть ли не по пальцам мог пересчитать исключения, например когда человек себе от спамеров ставил добавочную единицу (третий уровень) чтоб ему могли дозвониться и тому подобные вещи.

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

PostgreSQL функции для обработки номера телефона

  1. phone_parse.sql -- разбирает номер телефона в международном формате E.164 или в локальном формате на составные части (country_code, area_code, local_number)

  2. phone_normalize.sql -- нормализует номер телефона, возвращает номер телефона в международном формате E.164, например: +79651234567

  3. phone_format.sql -- форматирует номер телефона по образцу

PostgreSQL домен (тип данных)

  • phone.sql -- phone number in the international format E.164

Как в таком случае обрабатывать добавочные номера типа +123456789123#123?

Как в таком случае обрабатывать добавочные номера типа +123456789123#123?

Из статьи не понял, а лезть в стандарт лень - E.123 допускает оба варианта?:

(в начале статьи, и почему-то 9 цифр без кода страны)

+12 345 678 901

(в середине статьи)

+123456789012

Зарегистрируйтесь на Хабре, чтобы оставить комментарий