格式化电话号码(如果丢失则检测并添加国家/地区代码)

I have the following regex query that I built the idea is to take user input (phone numbers) and then make sure all the numbers are the exact same format when I store it in the database.

The problem I have is that this regex of mine does not cater for all the scenarios, I will explain in a bit.

This is my current code:

//format phone numbers
function Number_SA($number)
{
    //strip out everything but numbers
    $number =  preg_replace("/[^0-9]/", "", $number);
    //Strip out leading zeros:
    $number = ltrim($number, '0');
    //The default country code
    $default_country_code  = '+27';
    //Check if the number doesn't already start with the correct dialling code:
    if ( !preg_match('/^[+]'.$default_country_code.'/', $number)  ) {
        $number = $default_country_code.$number;
    }
    //return the converted number:
    return $number;
}

The behavior I want is the following; If a user enters any of the following formats the number should end up as +27

  • 797734809 #missing a leading 0
  • 0797734809
  • 27797734809
  • +27797734809

Should all be converted to:

  • +27797734809

PS: I first clean the number input with this:

function clean_input($data) 
{
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
}

And then I use the Number_SA($number) function on the number. In other words:

$number = clean_input($_POST["cell_number"]);
$msisdn = Number_SA($number);

PPS: Number_SA, the SA stands for South Africa since I live there and I want this to work for our country code which is +27

Solution, I ended up with @Kamil Kiełczewski answer by building it into my program as follows:

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (empty($_POST["cell_numbers"])) {
        $err = "Please add numbers!";
    } else {
        $numbers = test_input($_POST["cell_numbers"]);
        $numbers = explode("
", str_replace("", "", $numbers));
        foreach ($numbers as $number) {
            $msisdn = preg_replace('/^(?:\+27|27|0)?/','+27', $number);
            //insert into the database
        }        
    }
}

Here is your regexp:

^(?:\+27|27|0)?(\d*)

and if it match something use this: +27$1

Here is working example (improved): https://regex101.com/r/VaUAKN/7

EXPLANATION:

First we wanna split prefix (if exists) with number: ^(?:\+27|27|0)? the ?: inside group makes that prefix group will be ignored in results. The ^ means begining of line. The last ? allow prefix to not exists. And at the end (\d*) catch numbers after prefix

PHP working example (Wiktor Stribiżew noted that in regexp we can can omit (\d*) and $1 and change \+27|27 to \+?27 ):

$numOld = "2712345678";
$num = preg_replace('/^(?:\+?27|0)?/','+27', $numOld); // > $num = "+2712345678"

You can use a switch to check which format the number is in, and alter it accordingly:

<?php

$x = [
    '797734809',
    '0797734809',
    '27797734809',
    '0027797734809',
    '+27797734809',
];

function formatPhoneNo($no) {
    switch (true) {
        case (preg_match('#^7\d{8}$#', $no)):
            $no = '+27' . $no;
            break;
        case (preg_match('#^07\d{8}$#', $no)):
            $no = '+27' . substr($no, 1);
            break;
        case (preg_match('#^277\d{8}$#', $no)):
            $no = '+' . $no;
            break;
        case (preg_match('#^00277\d{8}$#', $no)):
            $no = '+' . substr($no, 2);
            break;
        case (preg_match('#^\+277\d{8}$#', $no)):
            break;
        default:
            throw new InvalidArgumentException('Invalid format supplied');
            break;
    }
    return $no;
}

foreach ($x as $y) {
    echo formatPhoneNo($y) . "
";
}

I added an extra format in your array, some people put 00 followed by the country code with no +. This outputs:

+27797734809 
+27797734809 
+27797734809 
+27797734809 
+27797734809

Which you can see here https://3v4l.org/ZVrNm