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

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

Ответы [ 8 ]

49 голосов
/ 10 марта 2011

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));
10 голосов
/ 10 октября 2008

Исходя из опыта написания подобных вещей, действительно сложно добиться 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
  • 0011 44 ​​78 1234 1234 (0011 - это стандартный международный телефонный код)
  • (44) 078 1234 1234 (не часто)

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

un (one), deux (two), trois (three), ...

его

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

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

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

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

3 голосов
/ 07 октября 2011

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

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 голос
/ 30 октября 2008

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

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

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

1 голос
/ 12 октября 2008

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

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

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

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

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

  4. Определите, имеет ли номер международный префикс набора номера для контекста страны - например, если исходным контекстом является Великобритания, я бы посмотрел, начинается ли он с «00», и заменил бы его на «+». В настоящее время я не проверяю, сопровождаются ли цифры, следующие за «00», международным телефонным кодом для целевой страны. Я ищу префикс международного набора для страны-источника в справочной таблице (например, GB -> '00', US -> '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, и что все преобразование выполняется программно.

0 голосов
/ 12 октября 2008

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

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

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

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

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

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

0 голосов
/ 10 октября 2008

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

Я видел несколько телефонов, которые ставили Q на клавишу 7 и Z на клавишу 9. Я видел несколько телефонов, которые ставят Q и Z на клавишу 0, а некоторые - на Q и Z на клавишу 1.

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

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

0 голосов
/ 09 октября 2008

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

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

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

...