Php номер телефона скобки
Ребята, подскажите как из номеров телефона удалить все лишние символы (скобки, тире, точки, пробелы и т.п., чтобы остались только цифры) и убрать код страны (+7 или 8).
Цитата (segazav @ 13.10.2014 — 14:41) |
как из номеров телефона удалить все лишние символы (скобки, тире, точки, пробелы и т.п., чтобы остались только цифры) |
$phone = preg_replace('#\D+#', '', $phone);
Ну мне просто нужно создать черный список номеров телефона для сайта, а некоторые указывают «+7» некоторые «8», а некоторые вообще не указывают код страны.
Цитата (segazav @ 13.10.2014 — 15:22) |
некоторые указывают «+7» некоторые «8», а некоторые вообще не указывают код страны. |
_____________
«Нужно быть готовым прислушиваться к тем, кто может тебя чему-нибудь научить. Иначе ты никогда не вырастешь.»
Откровенно я никому ниразу не нагрубил. А дать подзатыльник зарвавшемуся юнцу, так это и ему на пользу, и мне в удовольствие. © AllesKlar
Цитата (segazav @ 13.10.2014 — 11:22) |
Ну мне просто нужно создать черный список номеров телефона для сайта, а некоторые указывают «+7» некоторые «8», а некоторые вообще не указывают код страны. |
Если речь идет только о «наших» операторах, которые (+7 928 200 0000 ), то можно проверить длину телефона, и от нее, уже добавлять +7 если ничего нет, либо же исправлять 8 на +7.
Вот нельзя просто помочь и подсказать как удалить +7 или 8 обязательно нужна вот эта котовасия зачем и почему мож у него тех задание такое.
$phone = "+7 920-234-23-12";
//вырежет всё, кроме цифр
$phone = preg_replace("#[^\d]#", "", $phone);
//удалит код страны
$phone = substr($phone, 1);
echo $phone;
?>
_____________
HTML, CSS (Bootstrap), JS(JQuery, ExtJS), PHP, MySQL, MSSql, Posgres, (TSql, BI OLAP, MDX), Mongo, Git, SVN, CodeIgnater, Symfony, Yii 2, JiRA, Redmine, Bitbucket, Composer, Rabbit MQ, Amazon (SQS, S3, Transcribe), Docker
Цитата (waip @ 16.10.2014 — 10:50) |
Вот нельзя просто помочь и подсказать как удалить +7 или 8 обязательно нужна вот эта котовасия зачем и почему мож у него тех задание такое. |
потому что не все так просто, как тебе кажется. Если аудитория сайта не ограничена лишь одними россиянами, вылезут подводные камни, о которых ТС даже не догадывается.Да и .
Форматирование телефонных номеров на PHP
Возникла задача автоматического форматирования телефонных номеров в виде страна (город) номер, и первым делом я обратился к существующим решениям.
К сожалению, оказалось, что все найденные решения основываются на обычном подгоне строки под пользовательский формат, имея ограниченную область применения и ошибки при выходе за ее пределы.
Для начала приведу обзор найденных решений. Тем, кому это не интересно, рекомендую прокрутить ниже до заголовка «Форматы телефонных номеров» — там уже представлен мой вариант разбора номера с ссылкой на код.
Всеуничтожающий примитив
(Найденное решение. Мое ниже)
Первое, на что я наткнулся — были сообщения на форумах и банки скриптов, предлагающие решения следующего плана:
function phone_number( $sPhone ) <
$sPhone = ereg_replace( «[^0-9]» , » , $sPhone );
if (strlen( $sPhone ) != 10 ) return (False);
$sArea = substr( $sPhone , 0 , 3 );
$sPrefix = substr( $sPhone , 3 , 3 );
$sNumber = substr( $sPhone , 6 , 4 );
$sPhone = «(» . $sArea . «)» . $sPrefix . «-» . $sNumber ;
return ( $sPhone );
>
?>
Один из простых вариантов шустрого форматирования телефонных номеров, но каждое такое решение ориентировано на телефонные номера из конкретной локальной зоны и не является решением задачи.
Форматирование с помощью sscanf
function formatPhone( $phone ) if ( empty ( $phone )) return «» ;
if (strlen( $phone ) == 7 )
sscanf( $phone , «%3s%4s» , $prefix , $exchange );
else if (strlen( $phone ) == 10 )
sscanf( $phone , «%3s%3s%4s» , $area , $prefix , $exchange );
else if (strlen( $phone ) > 10 )
if (substr( $phone , 0 , 1 )== ‘1’ ) sscanf( $phone , «%1s%3s%3s%4s» , $country , $area , $prefix , $exchange );
>
else sscanf( $phone , «%3s%3s%4s%s» , $area , $prefix , $exchange , $extension );
>
else
return «unknown phone format: $phone» ;
$out = «» ;
$out .= isset ( $country )? $country . ‘ ‘ : » ;
$out .= isset ( $area )? ‘(‘ . $area . ‘) ‘ : » ;
$out .= $prefix . ‘-‘ . $exchange ;
$out .= isset ( $extension )? ‘ x’ . $extension : » ;
return $out ;
>
Не смотря на простое решение, эта функция уже умеет форматировать номера длиной 7, 10 и более цифр, но попадись ей номер из российской глубинки, она подавится и выдаст ошибочный результат.
Symfony, lib/helpers/PhoneHelper.php, format_phone
function format_phone( $phone = » , $convert = false , $trim = true )
// If we have not entered a phone number just return empty
if ( empty ( $phone )) return » ;
>
// Strip out any extra characters that we do not need only keep letters and numbers
$phone = preg_replace( «/[^0-9A-Za-z]/» , «» , $phone );
// Do we want to convert phone numbers with letters to their number equivalent?
// Samples are: 1-800-TERMINIX, 1-800-FLOWERS, 1-800-Petmeds
if ( $convert == true ) $replace = array ( ‘2’ => array ( ‘a’ , ‘b’ , ‘c’ ),
‘3’ => array ( ‘d’ , ‘e’ , ‘f’ ),
‘4’ => array ( ‘g’ , ‘h’ , ‘i’ ),
‘5’ => array ( ‘j’ , ‘k’ , ‘l’ ),
‘6’ => array ( ‘m’ , ‘n’ , ‘o’ ),
‘7’ => array ( ‘p’ , ‘q’ , ‘r’ , ‘s’ ),
‘8’ => array ( ‘t’ , ‘u’ , ‘v’ ), ‘9’ => array ( ‘w’ , ‘x’ , ‘y’ , ‘z’ ));
// Replace each letter with a number
// Notice this is case insensitive with the str_ireplace instead of str_replace
foreach ( $replace as $digit => $letters ) $phone = str_ireplace( $letters , $digit , $phone );
>
>
// If we have a number longer than 11 digits cut the string down to only 11
// This is also only ran if we want to limit only to 11 characters
if ( $trim == true && strlen( $phone )> 11 ) $phone = substr( $phone , 0 , 11 );
>
// Return original phone if not 7, 10 or 11 digits long
return $phone ;
>
?>
Функция позволяет не только форматировать в XXX-XXXX, (XXX) XXX-XXXX и X (XXX) XXX-XXXX, но и конвертировать номера, написанные цифрами. Ограниченность функции в форматировании номеров длиной 7, 10 и 11 символов никак не подходит.
Форматы телефонных номеров
Из вики-статьи видно, что никакого простого и удобного паттерна для быстрого форматирования всех номеров не существует. Коды стран регистрируются, подобно доменным зонам, а коды городов — остаются на совести каждой из стран.
Другими словами, маршрутизация звонков идет по маске, начиная с кода страны: звонок, направленный в конкретную страну далее пробивает себе маршрут в соответствии с кодами области, города, района и т.д. начиная с самой левой цифры, пока последнее звено не перебросит его на конкретный телефонный/факсовый аппарат. Проблема усложняется еще и тем, что коды городов внутри стран точно так же не поддаются единой сквозной стандартизации, т.е. в худшем из вариантов для правильного форматирования номеров придется использовать двумерный массив с кодами стран и их городов.
На самом деле, все оказалось не так страшно. В каждой стране можно разделить все коды городов на две части: на те, что в большинстве своем совпадают по длине, и все остальные. Этого достаточно, чтобы резко сократить область перебора кодов при сравнении. Т.е. можно создать массив из данных по каждой стране вида:
$data = Array(
‘Код страны’ =>Array(
‘name’ => ‘Имя страны’ , // для удобства. Не будет использоваться.
‘cityCodeLength’ => обычная_длина_кода_города_для_этой_страны,
‘exceptions’ =>Array(коды_городов_исключения),
)
);
?>
Затем провести предварительную обработку данных, дополнив его полями, сужающими область перебора, exceptions_max и exceptions_min — максимальной и минимальной длиной кода городов-исключений, соответственно. Также необходимо учесть страны, в которых коды городов начинаются на 0 — отразим эту «особенность» полем zeroHack. Как пример:
$data = Array(
‘886’ =>Array(
‘name’ => ‘Taiwan’ ,
‘cityCodeLength’ => 1 ,
‘zeroHack’ => false ,
‘exceptions’ =>Array( 89 , 90 , 91 , 92 , 93 , 96 , 60 , 70 , 94 , 95 ),
‘exceptions_max’ => 2 ,
‘exceptions_min’ => 2
),
);
?>
function phone( $phone = » , $convert = true , $trim = true )
global $phoneCodes ; // только для примера! При реализации избавиться от глобальной переменной.
if ( empty ( $phone )) return » ;
>
// очистка от лишнего мусора с сохранением информации о «плюсе» в начале номера
$phone =trim( $phone );
$plus = ( $phone [ 0 ] == ‘+’ );
$phone = preg_replace( «/[^0-9A-Za-z]/» , «» , $phone );
$OriginalPhone = $phone ;
foreach ( $replace as $digit => $letters ) $phone = str_ireplace( $letters , $digit , $phone );
>
>
// заменяем 00 в начале номера на +
if (substr( $phone , 0 , 2 )== «00» )
$phone = substr( $phone , 2 , strlen( $phone )- 2 );
$plus = true ;
>
// если телефон длиннее 7 символов, начинаем поиск страны
if (strlen( $phone )> 7 )
foreach ( $phoneCodes as $countryCode => $data )
$codeLen = strlen( $countryCode );
if (substr( $phone , 0 , $codeLen )== $countryCode )
// как только страна обнаружена, урезаем телефон до уровня кода города
$phone = substr( $phone , $codeLen , strlen( $phone )- $codeLen );
$zero = false ;
// проверяем на наличие нулей в коде города
if ( $data [ ‘zeroHack’ ] && $phone [ 0 ]== ‘0’ )
$zero = true ;
$phone = substr( $phone , 1 , strlen( $phone )- 1 );
>
$cityCode =NULL;
// сначала сравниваем с городами-исключениями
if ( $data [ ‘exceptions_max’ ]!= 0 )
for ( $cityCodeLen = $data [ ‘exceptions_max’ ]; $cityCodeLen >= $data [ ‘exceptions_min’ ]; $cityCodeLen —)
if (in_array(intval(substr( $phone , 0 , $cityCodeLen )), $data [ ‘exceptions’ ]))
$cityCode = ( $zero ? «0» : «» ).substr( $phone , 0 , $cityCodeLen );
$phone = substr( $phone , $cityCodeLen , strlen( $phone )- $cityCodeLen );
break ;
>
// в случае неудачи с исключениями вырезаем код города в соответствии с длиной по умолчанию
if (is_null( $cityCode ))
$cityCode = substr( $phone , 0 , $data [ ‘cityCodeLength’ ]);
$phone = substr( $phone , $data [ ‘cityCodeLength’ ], strlen( $phone )- $data [ ‘cityCodeLength’ ]);
>
// возвращаем результат
return ( $plus ? «+» : «» ). $countryCode . ‘(‘ . $cityCode . ‘)’ .phoneBlocks( $phone );
>
>
// возвращаем результат без кода страны и города
return ( $plus ? «+» : «» ).phoneBlocks( $phone );
>
// функция превращает любое число в строку формата XX-XX-. или XXX-XX-XX-. в зависимости от четности кол-ва цифр
function phoneBlocks( $number ) $add = » ;
if (strlen( $number )% 2 )
$add = $number [ 0 ];
$add .= (strlen( $number ) $number = substr( $number , 1 , strlen( $number )- 1 );
>
return $add .implode( «-» , str_split( $number , 2 ));
>
// тесты
echo phone( «+38 (044) 226-22-04» ). «
» ;
echo phone( «0038 (044) 226-22-04» ). «
» ;
echo phone( «+79263874814» ). «
» ;
echo phone( «4816145» ). «
» ;
echo phone( «+44 (0) 870 770 5370» ). «
» ;
echo phone( «0044 (0) 870 770 5370» ). «
» ;
echo phone( «+436764505509» ). «
» ;
echo phone( «(+38-048) 784-15-46 » ). «
» ;
echo phone( «(38-057) 706-34-03 » ). «
» ;
echo phone( «+38 (044) 244 12 01 » ). «
» ;
?>
, где global $phoneCodes; — тот самый массив с информацией по всем странам.
Функция полностью решает поставленную задачу.
Из недостатков функции следует отметить отсутствие анализа медленных участков с целью оптимизаци, а также обработки телефонных номеров, где есть код города, но нет кода страны (в этом случае достаточно бить на блоки функцией phoneBlocks или воспользоваться одним из решений выше). При использовании ее в какой-либо реализации необходимо заменить глобальную переменную на ссылку в параметре, а также можно доработать или заменить формат вывода, за который отвечает функция phoneBlocks.
Самое интересное
Используя информацию с сайтов:
http://www.mtt.ru/info/def/index.wbp
http://www.hella.ru/code/codeuro.htm
http://www.scross.ru/guide/phone-global/
я собрал массив данных по всем представленным странам, включая города-исключения, флаги zeroHack, а также коды мобильных сетей. Код можно загрузить здесь.
Быстродействие
Вопреки всем самым пессимистичным ожиданиям, код отрабатывает 10.000 номеров менее чем за 2 секунды.
- поддержка паттернов форматирования, принятых внутри конкретных стран («локально-принятые» нормы отображения номеров);
- добавление флага для указания, относительно какой страны выполнять форматирование номера;
- добавление параметра для указания формата вывода (в случае личных предпочтений и исключений);
- поддержка нелатинских буквенных номеров
- определение сотовых номеров и замена скобок на пробелы