Форматирование телефонных номеров в PHP

Я работаю над приложением SMS и должен иметь возможность конвертировать телефонный номер отправителя с +11234567890 в 123-456-7890, чтобы его можно было сравнить с записями в базе данных MySQL .

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

Как мне это сделать с PHP?

Благодаря!

$data = '+11234567890'; if( preg_match( '/^\+\d(\d{3})(\d{3})(\d{4})$/', $data, $matches ) ) { $result = $matches[1] . '-' .$matches[2] . '-' . $matches[3]; return $result; } 

Это американский форматировщик, который работает на более разных версиях, чем любой из текущих ответов.

 $numbers = explode("\n", '(111) 222-3333 ((111) 222-3333 1112223333 111 222-3333 111-222-3333 (111)2223333 +11234567890 1-8002353551 123-456-7890 -Hello! +1 - 1234567890 '); foreach($numbers as $number) { print preg_replace('~.*(\d{3})[^\d]{0,7}(\d{3})[^\d]{0,7}(\d{4}).*~', '($1) $2-$3', $number). "\n"; } 

И вот разбивка регулярного выражения:

 Cell: +1 999-(555 0001) .* zero or more of anything "Cell: +1 " (\d{3}) three digits "999" [^\d]{0,7} zero or up to 7 of something not a digit "-(" (\d{3}) three digits "555" [^\d]{0,7} zero or up to 7 of something not a digit " " (\d{4}) four digits "0001" .* zero or more of anything ")" 

Обновлено: 11 марта 2015 года использовать {0,7} вместо {,7}

Эта функция будет форматировать международные (10 + цифры), не-международные (10-значные) или старые школьные (7-значные) номера телефонов. Любые цифры, отличные от 10 +, 10 или 7 цифр, остаются неформатированными.

 function formatPhoneNumber($phoneNumber) { $phoneNumber = preg_replace('/[^0-9]/','',$phoneNumber); if(strlen($phoneNumber) > 10) { $countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10); $areaCode = substr($phoneNumber, -10, 3); $nextThree = substr($phoneNumber, -7, 3); $lastFour = substr($phoneNumber, -4, 4); $phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour; } else if(strlen($phoneNumber) == 10) { $areaCode = substr($phoneNumber, 0, 3); $nextThree = substr($phoneNumber, 3, 3); $lastFour = substr($phoneNumber, 6, 4); $phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour; } else if(strlen($phoneNumber) == 7) { $nextThree = substr($phoneNumber, 0, 3); $lastFour = substr($phoneNumber, 3, 4); $phoneNumber = $nextThree.'-'.$lastFour; } return $phoneNumber; } 

Предполагая, что ваши номера телефонов всегда имеют этот точный формат, вы можете использовать этот фрагмент:

 $from = "+11234567890"; $to = sprintf("%s-%s-%s", substr($from, 2, 3), substr($from, 5, 3), substr($from, 8)); 

Номера телефонов сложны. Для более надежного международного решения я бы рекомендовал этот хорошо поддерживаемый порт PHP библиотеки libphonenumber Google.

Используя это,

 use libphonenumber\NumberParseException; use libphonenumber\PhoneNumber; use libphonenumber\PhoneNumberFormat; use libphonenumber\PhoneNumberUtil; $phoneUtil = PhoneNumberUtil::getInstance(); $numberString = "+12123456789"; try { $numberPrototype = $phoneUtil->parse($numberString, "US"); echo "Input: " . $numberString . "\n"; echo "isValid: " . ($phoneUtil->isValidNumber($numberPrototype) ? "true" : "false") . "\n"; echo "E164: " . $phoneUtil->format($numberPrototype, PhoneNumberFormat::E164) . "\n"; echo "National: " . $phoneUtil->format($numberPrototype, PhoneNumberFormat::NATIONAL) . "\n"; echo "International: " . $phoneUtil->format($numberPrototype, PhoneNumberFormat::INTERNATIONAL) . "\n"; } catch (NumberParseException $e) { // handle any errors } 

вы получите следующий результат:

 Input: +12123456789 isValid: true E164: +12123456789 National: (212) 345-6789 International: +1 212-345-6789 

Я бы рекомендовал использовать формат E164 для E164 проверок. Вы также можете проверить, является ли номер фактически мобильным номером или нет (с использованием PhoneNumberUtil::getNumberType() ), или это даже номер в США (используя PhoneNumberUtil::getRegionCodeForNumber() ).

В качестве бонуса библиотека может обрабатывать практически любой ввод. Если вы, например, решили запустить 1-800-JETBLUE помощью приведенного выше кода, вы получите

 Input: 1-800-JETBLUE isValid: true E164: +18005382583 National: (800) 538-2583 International: +1 800-538-2583 

Neato.

Он работает так же хорошо для других стран, кроме США. Просто используйте другой код страны ISO в аргументе parse() .

Вот мое решение только для США, с региональным кодом в качестве необязательного компонента, требуемым разделителем для расширения и комментариями регулярных выражений:

 function formatPhoneNumber($s) { $rx = "/ (1)?\D* # optional country code (\d{3})?\D* # optional area code (\d{3})\D* # first three (\d{4}) # last four (?:\D+|$) # extension delimiter or EOL (\d*) # optional extension /x"; preg_match($rx, $s, $matches); if(!isset($matches[0])) return false; $country = $matches[1]; $area = $matches[2]; $three = $matches[3]; $four = $matches[4]; $ext = $matches[5]; $out = "$three-$four"; if(!empty($area)) $out = "$area-$out"; if(!empty($country)) $out = "+$country-$out"; if(!empty($ext)) $out .= "x$ext"; // check that no digits were truncated // if (preg_replace('/\D/', '', $s) != preg_replace('/\D/', '', $out)) return false; return $out; } 

И вот сценарий для проверки:

 $numbers = [ '3334444', '2223334444', '12223334444', '12223334444x5555', '333-4444', '(222)333-4444', '+1 222-333-4444', '1-222-333-4444ext555', 'cell: (222) 333-4444', '(222) 333-4444 (cell)', ]; foreach($numbers as $number) { print(formatPhoneNumber($number)."<br>\r\n"); } 

Я вижу, что это возможно с использованием какого-либо регулярного выражения или нескольких вызовов substr (при условии, что вход всегда имеет этот формат и не изменяет длину и т. Д.).

что-то вроде

 $in = "+11234567890"; $output = substr($in,2,3)."-".substr($in,6,3)."-".substr($in,10,4); 

должен это сделать.

Вот простая функция для форматирования телефонных номеров с 7-10 цифрами в более европейской (или шведской?) Манере:

 function formatPhone($num) { $num = preg_replace('/[^0-9]/', '', $num); $len = strlen($num); if($len == 7) $num = preg_replace('/([0-9]{2})([0-9]{2})([0-9]{3})/', '$1 $2 $3', $num); elseif($len == 8) $num = preg_replace('/([0-9]{3})([0-9]{2})([0-9]{3})/', '$1 - $2 $3', $num); elseif($len == 9) $num = preg_replace('/([0-9]{3})([0-9]{2})([0-9]{2})([0-9]{2})/', '$1 - $2 $3 $4', $num); elseif($len == 10) $num = preg_replace('/([0-9]{3})([0-9]{2})([0-9]{2})([0-9]{3})/', '$1 - $2 $3 $4', $num); return $num; } 

Попробуйте что-нибудь вроде:

 preg_replace('/\d{3}/', '$0-', str_replace('.', null, trim($number)), 2); 

это займет $ number 8881112222 и конвертируется в 888-111-2222 . Надеюсь это поможет.

Другой вариант – легко обновляется для получения формата из конфигурации.

 $numbers = explode("\n", '(111) 222-3333 ((111) 222-3333 1112223333 111 222-3333 111-222-3333 (111)2223333 +11234567890 1-8002353551 123-456-7890 -Hello! +1 - 1234567890 '); foreach( $numbers AS $number ){ echo comMember_format::phoneNumber($number) . '<br>'; } // ************************************************************************ // Format Phone Number public function phoneNumber( $number ){ $txt = preg_replace('/[\s\-|\.|\(|\)]/','',$number); $format = '[$1?$1 :][$2?($2):x][$3: ]$4[$5: ]$6[$7? $7:]'; if( preg_match('/^(.*)(\d{3})([^\d]*)(\d{3})([^\d]*)(\d{4})([^\d]{0,1}.*)$/', $txt, $matches) ){ $result = $format; foreach( $matches AS $k => $v ){ $str = preg_match('/\[\$'.$k.'\?(.*?)\:(.*?)\]|\[\$'.$k.'\:(.*?)\]|(\$'.$k.'){1}/', $format, $filterMatch); if( $filterMatch ){ $result = str_replace( $filterMatch[0], (!isset($filterMatch[3]) ? (strlen($v) ? str_replace( '$'.$k, $v, $filterMatch[1] ) : $filterMatch[2]) : (strlen($v) ? $v : (isset($filterMatch[4]) ? '' : (isset($filterMatch[3]) ? $filterMatch[3] : '')))), $result ); } } return $result; } return $number; } 

это занимает 7, 10 и 11 цифр, удаляет дополнительные символы и добавляет тире, переходя справа налево через строку. измените штрих на пробел или точку.

 $raw_phone = preg_replace('/\D/', '', $raw_phone); $temp = str_split($raw_phone); $phone_number = ""; for ($x=count($temp)-1;$x>=0;$x--) { if ($x === count($temp) - 5 || $x === count($temp) - 8 || $x === count($temp) - 11) { $phone_number = "-" . $phone_number; } $phone_number = $temp[$x] . $phone_number; } echo $phone_number; 

Все,

Думаю, я это исправил. Работа с текущими входными файлами и выполнение следующих двух функций:

function format_phone_number:

  function format_phone_number ( $mynum, $mask ) { /*********************************************************************/ /* Purpose: Return either masked phone number or false */ /* Masks: Val=1 or xxx xxx xxxx */ /* Val=2 or xxx xxx.xxxx */ /* Val=3 or xxx.xxx.xxxx */ /* Val=4 or (xxx) xxx xxxx */ /* Val=5 or (xxx) xxx.xxxx */ /* Val=6 or (xxx).xxx.xxxx */ /* Val=7 or (xxx) xxx-xxxx */ /* Val=8 or (xxx)-xxx-xxxx */ /*********************************************************************/ $val_num = self::validate_phone_number ( $mynum ); if ( !$val_num && !is_string ( $mynum ) ) { echo "Number $mynum is not a valid phone number! \n"; return false; } // end if !$val_num if ( ( $mask == 1 ) || ( $mask == 'xxx xxx xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '$1 $2 $3'." \n", $mynum); return $phone; } // end if $mask == 1 if ( ( $mask == 2 ) || ( $mask == 'xxx xxx.xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '$1 $2.$3'." \n", $mynum); return $phone; } // end if $mask == 2 if ( ( $mask == 3 ) || ( $mask == 'xxx.xxx.xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '$1.$2.$3'." \n", $mynum); return $phone; } // end if $mask == 3 if ( ( $mask == 4 ) || ( $mask == '(xxx) xxx xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '($1) $2 $3'." \n", $mynum); return $phone; } // end if $mask == 4 if ( ( $mask == 5 ) || ( $mask == '(xxx) xxx.xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '($1) $2.$3'." \n", $mynum); return $phone; } // end if $mask == 5 if ( ( $mask == 6 ) || ( $mask == '(xxx).xxx.xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '($1).$2.$3'." \n", $mynum); return $phone; } // end if $mask == 6 if ( ( $mask == 7 ) || ( $mask == '(xxx) xxx-xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '($1) $2-$3'." \n", $mynum); return $phone; } // end if $mask == 7 if ( ( $mask == 8 ) || ( $mask == '(xxx)-xxx-xxxx' ) ) { $phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', '($1)-$2-$3'." \n", $mynum); return $phone; } // end if $mask == 8 return false; // Returns false if no conditions meet or input } // end function format_phone_number 

function validate_phone_number:

  function validate_phone_number ( $phone ) { /*********************************************************************/ /* Purpose: To determine if the passed string is a valid phone */ /* number following one of the establish formatting */ /* styles for phone numbers. This function also breaks */ /* a valid number into it's respective components of: */ /* 3-digit area code, */ /* 3-digit exchange code, */ /* 4-digit subscriber number */ /* and validates the number against 10 digit US NANPA */ /* guidelines. */ /*********************************************************************/ $format_pattern = '/^(?:(?:\((?=\d{3}\)))?(\d{3})(?:(?<=\(\d{3})\))'. '?[\s.\/-]?)?(\d{3})[\s\.\/-]?(\d{4})\s?(?:(?:(?:'. '(?:e|x|ex|ext)\.?\:?|extension\:?)\s?)(?=\d+)'. '(\d+))?$/'; $nanpa_pattern = '/^(?:1)?(?(?!(37|96))[2-9][0-8][0-9](?<!(11)))?'. '[2-9][0-9]{2}(?<!(11))[0-9]{4}(?<!(555(01([0-9]'. '[0-9])|1212)))$/'; // Init array of variables to false $valid = array('format' => false, 'nanpa' => false, 'ext' => false, 'all' => false); //Check data against the format analyzer if ( preg_match ( $format_pattern, $phone, $matchset ) ) { $valid['format'] = true; } //If formatted properly, continue //if($valid['format']) { if ( !$valid['format'] ) { return false; } else { //Set array of new components $components = array ( 'ac' => $matchset[1], //area code 'xc' => $matchset[2], //exchange code 'sn' => $matchset[3] //subscriber number ); // $components = array ( 'ac' => $matchset[1], //area code // 'xc' => $matchset[2], //exchange code // 'sn' => $matchset[3], //subscriber number // 'xn' => $matchset[4] //extension number // ); //Set array of number variants $numbers = array ( 'original' => $matchset[0], 'stripped' => substr(preg_replace('[\D]', '', $matchset[0]), 0, 10) ); //Now let's check the first ten digits against NANPA standards if(preg_match($nanpa_pattern, $numbers['stripped'])) { $valid['nanpa'] = true; } //If the NANPA guidelines have been met, continue if ( $valid['nanpa'] ) { if ( !empty ( $components['xn'] ) ) { if ( preg_match ( '/^[\d]{1,6}$/', $components['xn'] ) ) { $valid['ext'] = true; } // end if if preg_match } else { $valid['ext'] = true; } // end if if !empty } // end if $valid nanpa //If the extension number is valid or non-existent, continue if ( $valid['ext'] ) { $valid['all'] = true; } // end if $valid ext } // end if $valid return $valid['all']; } // end functon validate_phone_number 

Заметьте, что у меня есть это в классе lib, поэтому, таким образом, вызов self: validate_phone_number из первой функции / метода.

Обратите внимание на строку # 32 функции validate_phone_number, где я добавил:

  if ( !$valid['format'] ) { return false; } else { 

чтобы получить мне ложное возвращение, если не действительный номер телефона.

Еще нужно проверить это на большее количество данных, но работать с текущими данными, с текущим форматом, и я использую стиль «8» для этой конкретной партии данных.

Также я прокомментировал логику «расширения», поскольку я постоянно получал от нее ошибки, видя, что у меня нет какой-либо информации в моих данных.

Это для стационарных телефонов в Великобритании без кода страны

 function format_phone_number($number) { $result = preg_replace('~.*(\d{2})[^\d]{0,7}(\d{4})[^\d]{0,7}(\d{4}).*~', '$1 $2 $3', $number); return $result; } 

Результат:

 2012345678 becomes 20 1234 5678 

Это быстро, чем Reg-Ex.

$ input = "0987654321";

echo $ output = substr ($ input, -10, -7). "-". substr ($ input, -7, -4). "-". substr ($ input, -4);

Я знаю, что OP запрашивает формат 123-456-7890, но, основываясь на ответе Джона Дула , я изменил его, чтобы вернуть номер телефона в круглых скобках, например (123) 456-7890. Он обрабатывает только 7 и 10 цифр.

 function format_phone_string( $raw_number ) { // remove everything but numbers $raw_number = preg_replace( '/\D/', '', $raw_number ); // split each number into an array $arr_number = str_split($raw_number); // add a dummy value to the beginning of the array array_unshift( $arr_number, 'dummy' ); // remove the dummy value so now the array keys start at 1 unset($arr_number[0]); // get the number of numbers in the number $num_number = count($arr_number); // loop through each number backward starting at the end for ( $x = $num_number; $x >= 0; $x-- ) { if ( $x === $num_number - 4 ) { // before the fourth to last number $phone_number = "-" . $phone_number; } else if ( $x === $num_number - 7 && $num_number > 7 ) { // before the seventh to last number // and only if the number is more than 7 digits $phone_number = ") " . $phone_number; } else if ( $x === $num_number - 10 ) { // before the tenth to last number $phone_number = "(" . $phone_number; } // concatenate each number (possibly with modifications) back on $phone_number = $arr_number[$x] . $phone_number; } return $phone_number; } с function format_phone_string( $raw_number ) { // remove everything but numbers $raw_number = preg_replace( '/\D/', '', $raw_number ); // split each number into an array $arr_number = str_split($raw_number); // add a dummy value to the beginning of the array array_unshift( $arr_number, 'dummy' ); // remove the dummy value so now the array keys start at 1 unset($arr_number[0]); // get the number of numbers in the number $num_number = count($arr_number); // loop through each number backward starting at the end for ( $x = $num_number; $x >= 0; $x-- ) { if ( $x === $num_number - 4 ) { // before the fourth to last number $phone_number = "-" . $phone_number; } else if ( $x === $num_number - 7 && $num_number > 7 ) { // before the seventh to last number // and only if the number is more than 7 digits $phone_number = ") " . $phone_number; } else if ( $x === $num_number - 10 ) { // before the tenth to last number $phone_number = "(" . $phone_number; } // concatenate each number (possibly with modifications) back on $phone_number = $arr_number[$x] . $phone_number; } return $phone_number; }