Каков наилучший способ преобразования телефонных номеров в международный формат (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)
Ответы
Ответ 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
Мы делаем что-то похожее на то, что вы описали, то есть разделите предоставленный номер телефона любых символов, отличных от цифр, а затем отформатируйте на основе различных правил, касающихся общей длины номера номера, кода внешнего доступа и кодов междугородного/международного доступа.