Каков наилучший способ преобразования телефонных номеров в международный формат (E.164) с использованием Java?

StackOverflow https://stackoverflow.com/questions/187216

Вопрос

Каков наилучший способ преобразования телефонных номеров в международный формат (E.164) с использованием Java?

Учитывая "номер телефона" и идентификатор страны (скажем, код страны ISO), я хотел бы преобразовать его в стандартный телефонный номер международного формата E.164.

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

Какой Java-фреймворк / библиотеку / утилиту вы бы порекомендовали для достижения этой цели?

P.S."Номером телефона" может быть что угодно, что может быть идентифицировано широкой публикой, например

* (510) 786-0404
* 1-800-GOT-MILK
* +44-(0)800-7310658

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

Номер формата E.164 должен быть полностью цифровым и использовать полный международный код страны (например, +44).

Это было полезно?

Решение

Google предоставляет библиотеку для работы с телефонными номерами.Тот же, который они используют для Android

http://code.google.com/p/libphonenumber/

String swissNumberStr = "044 668 18 00"
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
try {
  PhoneNumber swissNumberProto = phoneUtil.parse(swissNumberStr, "CH");
} catch (NumberParseException e) {
  System.err.println("NumberParseException was thrown: " + e.toString());
}

// Produces "+41 44 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.INTERNATIONAL));
// Produces "044 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.NATIONAL));
// Produces "+41446681800"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.E164));

Другие советы

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

Согласуются ли сопоставления символов с цифрами в разных странах?В США используется много этого (например, 1800-GOT-MILK), но в Австралии, например, это довольно редко.Что вам нужно было бы сделать, так это убедиться, что вы выполняли правильное сопоставление для данной страны, если оно меняется (может и не измениться).Я не знаю, что делают страны, использующие разные алфавиты (например, кириллицу в России и странах бывшего Восточного блока).;

Вы должны признать, что ваше решение не будет 100%-ным, и вам не следует ожидать, что оно будет таким.Вам нужно использовать подход "наилучшего предположения".Например, нет реального способа узнать, что 132345 является действительным телефонным номером в Австралии, как и 1300 123 456, но это единственные два шаблона, которые предназначены для номеров 13xx, и на них нельзя звонить из-за рубежа;

Вы также должны спросить, хотите ли вы подтвердить регионы (коды зон).Я полагаю, что в США используется система, в которой вторая цифра кода города равна 1 или 0.Возможно, когда-то так и было, но я не уверен, применимо ли это до сих пор.Как бы то ни было, во многих других странах будут действовать другие правила.В Австралии действительные коды городов для стационарных и мобильных телефонов состоят из двух цифр (первая равна 0).Все номера 08, 03 и 04 действительны.01 - это не так.Как вы справляетесь с этим?Ты этого хочешь?

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

  • (02) 1234 5678
  • 02 1234 5678
  • 0411 123 123 (но я никогда не видел 04 1112 3456)
  • 131 123
  • 13 1123
  • 131 123
  • 1 300 123 123
  • 1300 123 123
  • 02-1234-5678
  • 1300-234-234
  • +44 78 1234 1234
  • +44 (0)78 1234 1234
  • +44-78-1234-1234
  • +44-(0)78-1234-1234
  • 0011 44 78 1234 1234 (0011 - стандартный международный телефонный код)
  • (44) 078 1234 1234 (не распространенный)

И это просто не укладывается у меня в голове.Для одной страны.Во Франции, например, принято записывать номер телефона парами цифр (12 34 56 78), и они произносят его именно так:вместо того, чтобы:

un (один), deux (двое), trois (трое), ...

его

дузе (двенадцать), трент-катр (тридцать четыре), ...

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

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

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

Это было мое решение:

public static String FixPhoneNumber(Context ctx, String rawNumber)
{
    String      fixedNumber = "";

    // get current location iso code
    TelephonyManager    telMgr = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
    String              curLocale = telMgr.getNetworkCountryIso().toUpperCase();

    PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
    Phonenumber.PhoneNumber     phoneNumberProto;

    // gets the international dialling code for our current location
    String              curDCode = String.format("%d", phoneUtil.getCountryCodeForRegion(curLocale));
    String              ourDCode = "";

    if(rawNumber.indexOf("+") == 0)
    {
        int     bIndex = rawNumber.indexOf("(");
        int     hIndex = rawNumber.indexOf("-");
        int     eIndex = rawNumber.indexOf(" ");

        if(bIndex != -1)
        {
            ourDCode = rawNumber.substring(1, bIndex);
        }
        else if(hIndex != -1) 
        {               
            ourDCode = rawNumber.substring(1, hIndex);
        }
        else if(eIndex != -1)
        {
            ourDCode = rawNumber.substring(1, eIndex);
        }
        else
        {
            ourDCode = curDCode;
        }           
    }
    else
    {
        ourDCode = curDCode;
    }

    try 
    {
      phoneNumberProto = phoneUtil.parse(rawNumber, curLocale);
    } 

    catch (NumberParseException e) 
    {
      return rawNumber;
    }

    if(curDCode.compareTo(ourDCode) == 0)
        fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.NATIONAL);
    else
        fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.INTERNATIONAL);

    return fixedNumber.replace(" ", "");
}

Я надеюсь, что это поможет кому-то с той же проблемой.

Наслаждайтесь и используйте свободно.

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

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

  1. Удалить все пробелы из числа

  2. Переведите все буквы в цифры, используя таблицу преобразования букв в цифры (например,A-->2, B-->2, C-->2, D-->3) и т.д.для клавиатуры (я не знал, что некоторые клавиатуры распределяют их по-разному)

  3. Удалите все знаки препинания, сохранив предшествующий знак «+», если он существует (в случае, если число уже находится в каком-то международном формате).

  4. Определите, имеет ли номер международный префикс набора для контекста страны - например.если исходным контекстом является Великобритания, я бы посмотрел, начинается ли он с «00», и заменил его на «+».В настоящее время я не проверяю, следуют ли за цифрами после «00» международный телефонный код целевой страны.Я ищу международный префикс набора номера страны происхождения в справочной таблице (например,Великобритания --> «00», США --> «011» и т. д.)

  5. Определите, имеет ли номер префикс местного набора для контекста страны, напримересли исходным контекстом является Великобритания, я бы посмотрел, начинается ли он с «0», и заменил его на «+», за которым следует международный телефонный код целевой страны.Я ищу местный префикс набора номера исходной страны в справочной таблице (например,GB-->'0', US-->'1' и т. д.), а также международный телефонный код целевой страны в другой справочной таблице (например, 'GB'='44', US='1').

Кажется, это работает для всего, что я пробовал до сих пор - за исключением ситуации с +44 (0) 1234-567-890 - для нее я добавлю специальную проверку.

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

Телефонные компании, похоже, сталкиваются с этой проблемой каждый день.Я никогда не получаю противоречивых результатов при наборе номеров через PSTN.Например, в США (где мобильные телефоны имеют те же коды городов, что и стационарные телефоны), я могу набрать +1-123-456-7890 или 011-1-123-456-7890 (где 011 — международный префикс набора номера в США, а 1 — международный телефонный код США), 1-123-456-7890 (где 1 — префикс местного набора номера в США) или даже 456-7890 (при условии, что в тот момент я находился в коде города 123) и каждый раз получать одни и те же результаты.Я предполагаю, что внутри эти набранные номера преобразуются в тот же стандартный формат E.164, и что все преобразование выполняется программно.

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

Формат +44(0)800, который иногда (неправильно) используется в Великобритании, раздражает и не является строго допустимым в соответствии с E.123, который является рекомендацией ITU-T относительно того, как следует отображать числа.Если у вас нет копии E.123, стоит посмотреть.

Как бы то ни было, сама телефонная сеть не всегда использует E.164.Часто в сигнализации ISDN, генерируемой УАТС (или в сети, если вы используете телефон Steam), присутствует флаг, который сообщает сети, является ли набираемый номер местным, национальным или международным.

Это очень сложная задача, поскольку почти в каждой стране номера телефонов пишутся по-разному.

Раньше мы сохраняли список REGEXP (мы поддерживали 19 форматов) для анализа трех частей числа, а затем преобразовывали эти три части в «+{1} {2} {3}».

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

В некоторых странах вы можете подтвердить 112 как действительный номер телефона, но если вы вставите перед ним код страны, он больше не будет действительным.В других странах вы не можете подтвердить номер 112, но можете подтвердить 911 как действительный номер телефона.

Я видел некоторые телефоны, в которых Q на клавише 7 и Z на клавише 9.Я видел некоторые телефоны, в которых Q и Z помещаются на клавишу 0, и некоторые, в которых Q и Z помещаются на клавишу 1.

Код города, существовавший вчера, может не существовать сегодня, и наоборот.

В половине Северной Америки (код страны 1) правило второй цифры раньше было 0 или 1 для кодов городов, но это правило исчезло 10 лет назад.

Мне неизвестна стандартная библиотека или платформа для форматирования телефонных номеров в E.164.

Решение, используемое для нашего продукта, которое требует форматирования идентификатора вызывающего абонента, предоставленного УАТС, в E.164, заключается в развертывании файла (таблицы базы данных), содержащего информацию о формате E.164 для всех применимых стран.Преимущество этого заключается в том, что приложение можно обновлять (чтобы обрабатывать все необычные ситуации в различных сетях PSTN) без необходимости внесения изменений в базу производственного кода.

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

В качестве примера таблицы используется абонентская группа PSTN Новой Зеландии (частичная).

CC  AREA_CODE  AREA_CODE_LENGTH  SUBSCRIBER  SUBSCRIBER_LENGTH
64                            1              7
64         21                 2              7
64        275                 3              6

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top