Formatowanie numerów telefonów w PHP

102

Pracuję nad aplikacją do obsługi SMS - ów i muszę mieć możliwość konwersji numeru telefonu nadawcy z +11234567890 na 123-456-7890, aby można go było porównać z rekordami w bazie danych MySQL .

Liczby są przechowywane w tym drugim formacie do wykorzystania w innym miejscu na stronie i wolałbym nie zmieniać tego formatu, ponieważ wymagałoby to modyfikacji dużej ilości kodu.

Jak mam się do tego zabrać z PHP?

Dzięki!

NightMICU
źródło
13
ahhhhh .... NIEEEE .... dlaczego przechowujesz takie numery telefonów !? jako ciąg? Zły zły zły! Powinieneś przechowywać je jako duże int ... mniej wymaganego miejsca, szybszy indeks, szybsze sortowanie
sethvargo
7
nie tyle problem z przechowywaniem numerów telefonów, ile ciągów (nie da się tego uniknąć, gdy trzeba przechowywać +61 (0) 812345678) - ale przechowywanie określonego formatu jest nieco podejrzane (tj. separatory) - najlepiej formatować na warstwie prezentacji, a nie na warstwie danych.
HorusKol,
3
@NightMICU - to w 100% zły sposób na zrobienie tego ... Powinieneś przechowywać jako liczbę całkowitą i mieć funkcję wielokrotnego użytku, która formatuje do wyświetlania
sethvargo
229
Przechowywanie numerów telefonów jako liczb całkowitych w celu zaoszczędzenia miejsca to okropny pomysł. Numery telefonów nie są liczbami w ogólnym sensie, że będziesz na nich liczyć. W momencie, gdy będziesz musiał przechowywać liczby poza formatem specyficznym dla USA, w którym liczba może zaczynać się od 0, napotkasz problemy. Lepiej jest przechowywać te informacje jako ciąg.
Charles Sprayberry
2
@NightMICU Jeśli to sprawia, że ​​czujesz się lepiej zapisując jako ciąg, nawet wielki Jon Skeet mówi, aby nie przechowywać jako liczby całkowitej dla wiodącego problemu zera. stackoverflow.com/a/3483166/746010
Charles Sprayberry

Odpowiedzi:

109
$data = '+11234567890';

if(  preg_match( '/^\+\d(\d{3})(\d{3})(\d{4})$/', $data,  $matches ) )
{
    $result = $matches[1] . '-' .$matches[2] . '-' . $matches[3];
    return $result;
}
slider
źródło
Aby uchwycić możliwe spacje i inne formaty numerów międzynarodowych: / ^ (\ +? \ D {1,2}?) [.-]? (? (\ D {3}))? [.-]? (\ D {3}) [.-]? (\ D {4}) $ /
TeckniX
3
@stoutie źle, $ pasuje [0] to cały dopasowany tekst wzorca, a następnie musisz zmienić array_shift ($ pasuje) przed użyciem go w ten sposób.
Alexandre Reis Ribeiro
Czy szybsze byłoby sformatowanie tego na wyjściu? Używasz sprintflub `` printf ''? Niech mi ktoś wyjaśni. Pracuję tylko z numerami telefonów w USA i nie sądzę, aby przepuszczanie ich przez funkcję wyjściową przy użyciu podłańcucha było najlepszą metodą.
Rafael
Myślę, że SO powinno zawierać głosy przeciw w komentarzach. Komentarz @Stoutie jest mylący.
peterchaula
1
Przepraszam za moje młodsze, błędne komentarze sprzed dnia tdd, które wiele lat temu zamieszczały we własnym zakresie. Obiecuję, że w przyszłości będzie lepiej. Wydaje się, że komentarz, do którego się odnosisz, został usunięty. Wszystko dobrze. Wesołych Świąt.
Stoutie
164

To jest amerykański program do formatowania telefonów, który działa na większej liczbie wersji liczb niż jakiekolwiek bieżące odpowiedzi.

$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";
}

A oto podział wyrażenia regularnego:

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

Zaktualizowano: 11 marca 2015 r. Do użycia {0,7}zamiast{,7}

Xeoncross
źródło
Co jeśli numer telefonu ma rozszerzenie?
SpYk3HH
1
Słuszna uwaga - czy mamy kilka przykładów tego, jak rozszerzenia wyglądają na całym świecie? Proabaly coś w stylu ~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})(?:[ \D#\-]*(\d{3,6}))?.*~.
Xeoncross
1
Co się stanie, jeśli użytkownicy mojej witryny internetowej pominęli numer kierunkowy?
skibulk
Czy możemy uzyskać zestawienie tego, co robią różne części wyrażenia regularnego (jak pokazano poniżej w innej odpowiedzi)? czyli: (\d{3}) // 3 digits [\d]// znak, który nie jest cyfrą
roberthuttinger
1
@WesleyMurch Wydaje się, że nastąpiła zmiana w dopasowaniu wyrażenia regularnego, która teraz wymaga {,7}aktualizacji {0,7}. Zaktualizowałem kod.
Xeoncross
55

Ta funkcja formatuje numery telefonów międzynarodowe (ponad 10 cyfr), nie-międzynarodowe (10 cyfr) lub oldschoolowe (7 cyfr). Wszystkie liczby inne niż 10+, 10 lub 7 cyfr pozostaną niesformatowane.

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;
}
Bryan Schoen
źródło
To świetnie, ale chciałbym tylko zaznaczyć, że nawiasy wokół numeru kierunkowego oznaczają opcjonalne liczby. W większości jurysdykcji numer kierunkowy nie jest już opcjonalny, więc oddzielanie go prostym myślnikiem jest dokładniejsze.
Vincent
30

Zakładając, że Twoje numery telefonów zawsze mają dokładnie ten format, możesz użyć tego fragmentu:

$from = "+11234567890";
$to = sprintf("%s-%s-%s",
              substr($from, 2, 3),
              substr($from, 5, 3),
              substr($from, 8));
Daniel Hepper
źródło
Po prostu powtórz $ do var ... Uwielbiam to, działało dla mnie po prostu prefekt.
Samuel Ramzan
22

Numery telefonów są trudne. Aby uzyskać bardziej niezawodne, międzynarodowe rozwiązanie, poleciłbym ten dobrze utrzymany port PHP biblioteki libphonenumber firmy Google .

Używając tego w ten sposób,

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
}

otrzymasz następujący wynik:

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

Zalecam użycie E164formatu do podwójnych kontroli. Możesz również sprawdzić, czy jest to numer telefonu komórkowego, czy nie (używając PhoneNumberUtil::getNumberType()), czy nawet numer amerykański (używając PhoneNumberUtil::getRegionCodeForNumber()).

Dodatkowo biblioteka może obsłużyć prawie każde wejście. Jeśli, na przykład, zdecydujesz się uruchomić 1-800-JETBLUEpowyższy kod, otrzymasz

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

Neato.

Działa równie dobrze w krajach innych niż Stany Zjednoczone. Po prostu użyj innego kodu kraju ISO w parse()argumencie.

likeitlikeit
źródło
2
Świetna biblioteka, ale pamiętaj, że ma 37 MB i 1500 plików! W moim przypadku mam ograniczoną liczbę numerów telefonów do sformatowania, dlatego zdecydowałem się po prostu dodać number_formattedkolumnę w mojej bazie i ręcznie wpisać sformatowane numery. Nadal używam libphonenumberlokalnie do generowania sformatowanych liczb, ale włączenie tak ogromnej biblioteki do mojego małego projektu jest po prostu przesadą.
Magnus W
9

Oto moje rozwiązanie tylko w USA, z numerem kierunkowym jako opcjonalnym składnikiem, wymaganym ogranicznikiem dla rozszerzenia i komentarzami do wyrażenia regularnego:

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

A oto skrypt do przetestowania:

$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");
}
skibulk
źródło
5

Oto prosta funkcja formatowania numerów telefonów zawierających od 7 do 10 cyfr w bardziej europejski (lub szwedzki?) Sposób:

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;
}
Zeromatik
źródło
5

Nie wynajduj koła na nowo! Zaimportuj tę niesamowitą bibliotekę:
https://github.com/giggsey/libphonenumber-for-php

$defaultCountry = 'SE'; // Based on the country of the user
$phoneUtil = PhoneNumberUtil::getInstance();
$swissNumberProto = $phoneUtil->parse($phoneNumber, $defaultCountry);

return $phoneUtil->format($swissNumberProto, PhoneNumberFormat::INTERNATIONAL);

Opiera się na bibliotece Google do analizowania, formatowania i sprawdzania międzynarodowych numerów telefonów: https://github.com/google/libphonenumber

Viktor Jarnheimer
źródło
3
Myślę, że jest to poprawna odpowiedź, ale jeśli chcesz, aby była przydatna zgodnie ze standardami przepełnienia stosu, powinieneś edytować, aby dołączyć przykład rozwiązujący problem OP przy użyciu biblioteki, a nie tylko udostępniać łącze.
Alecg_O
1
Dziękuję @Alecg_O! Dodałem przykład.
Viktor Jarnheimer
4

Widzę, że jest to możliwe przy użyciu jakiegoś wyrażenia regularnego lub kilku wywołań substr (zakładając, że dane wejściowe są zawsze w tym formacie i nie zmieniają długości itp.)

coś jak

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

powinien to zrobić.

Ali Lown
źródło
4

Jest szybszy niż RegEx.

$input = "0987654321"; 

$output = substr($input, -10, -7) . "-" . substr($input, -7, -4) . "-" . substr($input, -4); 
echo $output;
Rishabh
źródło
1
Krótkie i słodkie (y).
rahim.nagori
2

Spróbuj czegoś takiego:

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

zajęłoby to liczbę $ 8881112222i zostało przekonwertowane na 888-111-2222. Mam nadzieję że to pomoże.

RobertPitt
źródło
1
Źródło Twojej sugestii: hotscripts.com/forums/php/36805-php-format-phone-numbers.html . Str_replace of '.'powinien również zostać zaktualizowany '-'lub usunięty. Zostało dołączone ze względu na konkretny przypadek użycia - przy niewielkim wysiłku można było go przekonwertować preg_replace('/\d{3}/', '$0-', substr($number, 2))i bezpośrednio odpowiedzieć na pytanie.
Iiridayn,
2

Inna opcja - łatwa aktualizacja, aby otrzymać format z konfiguracji.

$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;
}
David H.
źródło
1

Wszystko,

Chyba to naprawiłem. Pracuje dla bieżących plików wejściowych i ma następujące 2 funkcje, aby to zrobić!

funkcja format_numer_telefonu:

        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

funkcja 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

Zauważ, że mam to w bibliotece klasy, więc wywołanie „self :: validate_phone_number” z pierwszej funkcji / metody.

Zwróć uwagę na wiersz # 32 funkcji „validate_phone_number”, w którym dodałem:

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

aby otrzymać fałszywy zwrot, jeśli nie jest to ważny numer telefonu.

Nadal muszę to przetestować na większej ilości danych, ale pracuję na bieżących danych, z aktualnym formatem i używam stylu „8” dla tej konkretnej partii danych.

Skomentowałem także logikę „rozszerzenia”, ponieważ ciągle otrzymywałem błędy, widząc, że nie mam żadnej z tych informacji w moich danych.

OldManRiver
źródło
1

zajmuje to 7, 10 i 11 cyfr, usuwa dodatkowe znaki i dodaje myślniki, przechodząc od prawej do lewej przez ciąg. zamień myślnik na spację lub kropkę.

$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;
John Dul
źródło
1

Wiem, że OP żąda formatu 123-456-7890, ale na podstawie odpowiedzi Johna Dula zmodyfikowałem go tak, aby zwracał numer telefonu w nawiasach, np. (123) 456-7890. Ten obsługuje tylko liczby 7 i 10 cyfrowe.

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;
}
Andrew Tibbetts
źródło
1

Oto moja opinia:

$phone='+11234567890';
$parts=sscanf($phone,'%2c%3c%3c%4c');
print "$parts[1]-$parts[2]-$parts[3]";

//  123-456-7890

sscanfFunkcja przyjmuje jako drugi parametr ciąg formatu informując go, jak interpretować znaki od pierwszego łańcucha. W tym przypadku oznacza to 2 znaki ( %2c), 3 znaki, 3 znaki, 4 znaki.

Zwykle sscanffunkcja zawierałaby również zmienne do przechwytywania wyodrębnionych danych. Jeśli nie, dane są zwracane w tablicy, którą wywołałem $parts.

printOświadczenie wyprowadza interpolowanej ciąg. $part[0]jest ignorowany.

Użyłem podobnej funkcji do formatowania australijskich numerów telefonów.

Zwróć uwagę, że z punktu widzenia przechowywania numeru telefonu:

  • numery telefonów są ciągami
  • przechowywane dane nie powinny zawierać formatowania, takiego jak spacje czy łączniki
Manngo
źródło
To najbardziej eleganckie i czytelne rozwiązanie. POCAŁUNEK. Nie przewijaj dalej, jeśli ciągi wejściowe zawsze mają ten sam wzorzec. Dziękuję za ten dodatek.
Musa
1

Formaty telefonów w Wielkiej Brytanii

W przypadku aplikacji, którą opracowałem, zauważyłem, że ludzie wpisywali swój numer telefonu „poprawnie” z postaci czytelnej dla człowieka, ale wstawiali różne losowe znaki, takie jak „-” / „+44” itp. Problem polegał na tym, że aplikacja w chmurze, która trzeba było porozmawiać, był dość konkretny co do formatu. Zamiast używać wyrażenia regularnego (może to być frustrujące dla użytkownika), stworzyłem klasę obiektu, która przetwarza wprowadzoną liczbę do prawidłowego formatu przed przetworzeniem przez moduł trwałości.

Format danych wyjściowych zapewnia, że ​​każde oprogramowanie odbierające interpretuje dane wyjściowe jako tekst, a nie jako liczbę całkowitą (która natychmiast straciłaby wiodące zero), a format jest zgodny z British Telecoms wskazówki dotyczące formatowania liczb - co również ułatwia zapamiętywanie przez ludzi, dzieląc dużą liczbę na małe, łatwe do zapamiętania grupy.


+441234567890 produkuje (01234)
567890 02012345678 produkuje (020) 1234 5678
1923123456 produkuje (01923) 123 456
01923123456 produkuje (01923) 123 456
01923, to jest tekst123456 produkuje (01923) 123 456

Znaczenie segmentu giełdy numeru - w nawiasach - polega na tym, że w Wielkiej Brytanii i większości innych krajów połączenia między numerami w tej samej centrali można wykonywać z pominięciem segmentu giełdy. Nie dotyczy to jednak numerów telefonów z serii 07, 08 i 09.

Jestem pewien, że są bardziej wydajne rozwiązania, ale ten okazał się wyjątkowo niezawodny. Więcej formatów można łatwo dostosować, dodając na końcu funkcję teleNum.

W ten sposób procedura jest wywoływana ze skryptu wywołującego

$telephone = New Telephone;
$formattedPhoneNumber = $telephone->toIntegerForm($num)

`

<?php
class   Telephone 
{   
    public function toIntegerForm($num) {
        /*
         * This section takes the number, whatever its format, and purifies it to just digits without any space or other characters
         * This ensures that the formatter only has one type of input to deal with
         */
        $number = str_replace('+44', '0', $num);
        $length = strlen($number);
        $digits = '';
        $i=0;
        while ($i<$length){
            $digits .= $this->first( substr($number,$i,1) , $i);
            $i++;
        }
        if (strlen($number)<10) {return '';}
        return $this->toTextForm($digits);
    }
    public function toTextForm($number) {

        /*
         * This works on the purified number to then format it according to the group code
         * Numbers starting 01 and 07 are grouped 5 3 3
         * Other numbers are grouped 3 4 4 
         * 
         */
        if (substr($number,0,1) == '+') { return $number; }
        $group = substr($number,0,2);
        switch ($group){
            case "02" :
                $formattedNumber = $this->teleNum($number, 3, 4); // If number commences '02N' then output will be (02N) NNNN NNNN
                break;
            default :
                $formattedNumber = $this->teleNum($number, 5, 3); // Otherwise the ooutput will be (0NNNN) NNN NNN
        }
        return $formattedNumber;

    }
    private function first($digit,$position){
        if ($digit == '+' && $position == 0) {return $digit;};
        if (!is_numeric($digit)){
            return '';
        }
        if ($position == 0) {
            return ($digit == '0' ) ? $digit :  '0'.$digit;
        } else {
            return $digit;
        } 
    }
    private function teleNum($number,$a,$b){
        /*
         * Formats the required output 
         */
        $c=strlen($number)-($a+$b);
        $bit1 = substr($number,0,$a);
        $bit2 = substr($number,$a,$b);
        $bit3 = substr($number,$a+$b,$c);
        return '('.$bit1.') '.$bit2." ".$bit3;
    }
}
Mike M0ITI
źródło
0

Dotyczy telefonów stacjonarnych w Wielkiej Brytanii bez numeru kierunkowego kraju

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

Wynik:

2012345678
becomes
20 1234 5678
typocoder
źródło
0

Proszę spojrzeć na funkcję opartą na substracie, która może zmieniać formaty

function phone(string $in): string
{
    $FORMAT_PHONE = [1,3,3,4];
    $result =[];
    $position = 0;
    foreach ($FORMAT_PHONE as $key => $item){
        $result[] = substr($in, $position, $item);
        $position += $item;
    }
    return '+'.implode('-',$result);
}
Yevgeniy Afanasyev
źródło
0

Sprawdź numer telefonu

$phone = '+385 99 1234 1234'

$str = preg_match('/^\+?\d{1,3}[\s-]?\d{1,3}[\s-]?\d{1,4}[\s-]?\d{1,4}$/', $phone);

if($str){
return true;
}else{
return false;
}
łatwy sklep
źródło