Подтвердить что ты не робот

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

Каков наилучший способ преобразования телефонных номеров в международный формат (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)

4b9b3361

Ответ 1

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));

Ответ 2

Говоря об опыте написания такого рода вещей, это действительно сложно сделать со 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 (три),...

его

douze (двенадцать), trente-quatre (тридцать четыре),...

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

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

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

Ответ 3

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

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(" ", "");
}

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

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

Ответ 4

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

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

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

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

  • Разделите все знаки пунктуации - сохранив предыдущий "+" , если он существует (если номер уже находится в каком-то международном формате).

  • Определите, имеет ли номер префикс международного набора для контекста страны - например, если исходный контекст - это Великобритания, я бы посмотрел, начнется ли оно с "00", и замените его "+" . В настоящее время я не проверяю, следуют ли цифры, следующие за "00", международным кодом набора для целевой страны. Я просматриваю префикс международного набора для страны-источника в справочной таблице (например, GB → '00', US → '011' и т.д.)

  • Определите, имеет ли номер префикс локального набора для контекста страны - например, если исходный контекст - это Великобритания, я бы посмотрел, начнет ли он с "0", и заменит его "+" , за которым следует международный код набора для целевой страны. Я просматриваю префикс локального набора для страны-источника в справочной таблице (например, GB → '0', US → '1' и т.д.) И международный код набора для целевой страны в другой таблице поиска ( eg'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 и что преобразование выполняется в программном обеспечении.

Ответ 5

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

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

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

Ответ 6

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

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

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

Ответ 7

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

Я видел некоторые телефоны, которые положили Q на 7-й ключ и Z на клавишу 9. Я видел некоторые телефоны, которые положили Q и Z на клавишу 0, а некоторые, которые положили Q и Z на клавишу 1.

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

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

Ответ 8

Мне не известно о стандартной библиотеке или структуре, доступной для форматирования телефонных номеров в 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

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