Чистый код Короткие заметки веб-разработчика

Как искать, распознавать и нормализовать телефонные номера в JavaScript (и других языках)

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

Для начала, определимся с рамками задачи. Во-первых, телефоны должны быть одной страны. В нашем случае — российские номера (код России +7). Это правило сильно упростит жизнь. Также, номера могут иметь совершенно разные разделители и быть в разных форматах:

  • Без плюса: 79001234567
  • Без семерки: 9001234567
  • Через восьмерку: 89001234567
  • Скобки: 8(900)1234567, +7 (900) 123-45-67
  • Пробелы: 8 900 123 45 67, +7 (900) 123 45 67
  • Дефисы: 8-900-123-45-67, +7-900-123-45-67
  • Точки: 8.900.123.45.67, 900.123.45.67

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

Сразу скажу, что все эти случае покрывает библиотека libphonenumber от Google. У библиотеки есть порты для многих языков (PHP, C#, Go, Swift, Python, Ruby аж 3 штуки, Rust и других), ссылки на них есть на странице проекта в GitHub. Проблема решения от Google в том, что мы не может из коробки искать номера по тексту. Да, без сомнения, если пользователь указывает номер в специальном поле, библиотека от Google становится очень полезной. Но если пользователь указывает телефон в тексте или задача вообще состоит из парсинга номеров с сайта, то решение Google нам не подойдёт.

Тем не менее, подойдёт более быстрая и простая (по утверждению автора) реализация для JavaScript libphonenumber-js. В прекрасном демо этой библиотеки можно поиграться с различными типами номеров и проверить работоспособность:

Как видите, библиотека отлично справляется с поиском и распознаванием номеров. Она даже сможет подсказать вам некоторые особенности. Такие как различные форматы, удобные жителям той страны, в которой выпущен номер. Тип номера (мобильный, домашний, бесплатный, он же TOLL_FREE), а так же длину номера и его валидность. Например, не бывает номеров российских, начинающихся с +710.

Собственно, пример кода:

import { findPhoneNumbersInText } from 'libphonenumber-js'

const phones = findPhoneNumbersInText(`Тест с номерами 8(900)1234567, а так же 900.123.45.67`, 'RU')
console.log(phones)
//phones будет содержать:
const phones = [                                  
  {                                
    startsAt: 16,                  
    endsAt: 29,                    
    number: PhoneNumber {          
      country: 'RU',               
      countryCallingCode: '7',     
      nationalNumber: '9001234567',
      number: '+79001234567'
    }
  },
  {
    startsAt: 40,
    endsAt: 53,
    number: PhoneNumber {
      country: 'RU',
      countryCallingCode: '7',
      nationalNumber: '9001234567',
      number: '+79001234567'
    }
  }
]

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