David Wyly
David Wyly

Reputation: 1701

splitting a string into a phone number and extension using preg_match

So I'm trying to split a string that contains a phone number and extension, as sometimes an extension exists in the string. This is my attempt:

$tests[] = "941-751-6550 ext 2204";
$tests[] = "(941) 751-6550 ext 2204";
$tests[] = "(941)751-6550 ext 2204";
$tests[] = "9417516550 ext 2204";
$tests[] = "941-751-6550 e 2204";
$tests[] = "941-751-6550 ext 2204 ";
$tests[] = "941-751-6550 extension 2204";
$tests[] = "941-751-6550 x2204";
$tests[] = "(941) 751-6550";
$tests[] = "(941)7516550";
$tests[] = "941-751-6550 ";
$tests[] = "941-751-6550";

foreach ($tests as $test) {
    preg_match('#([\(\)\s0-9\-]+)(.+$)#',$test,$matches);
    $phone = preg_replace('#[\-\(\)\s]#','',$matches[1]);
    $extension = preg_replace('#[^0-9]#','',$matches[2]);
    if ($phone == '9417516550' 
        && ($extension == '2204' 
            || $extension == '0')) {
                echo "PASS: phone: $phone ext: $extension<br />";
    } else {
        echo "FAIL: phone: $phone ext: $extension<br />";
    }
}

However, when I run these tests to see if it properly splits the phone number and the extension, I get the following output:

PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
FAIL: phone: 941751655 ext: 0
FAIL: phone: 941751655 ext: 0
FAIL: phone: 9417516550 ext: 
FAIL: phone: 941751655 ext: 0

As you can see, it breaks when I exclude an extension altogether (the last four tests). How might I correct the preg_match() regex so that the FAIL: ... lines look like PASS: phone: 9417516550 ext: 0?

Upvotes: 1

Views: 235

Answers (6)

T.J. Compton
T.J. Compton

Reputation: 405

Honestly, you're better off stripping the non-numeric characters, then splitting off anything after the first 10 as the extension. It's conceptually equivalent, but more straightforward and foolproof, and more efficient than running through multiple regexes, which are inherently slow.

foreach($tests as $test){
    $phone = preg_replace("/[^0-9]/", "", $test);
    $extension = substr($phone,10);
    $phone = substr($phone,0,10);
    if(empty($extension)){
         $extension = '0';
    }
    if ($phone == '9417516550'
        && ($extension == '2204'
            || $extension == '0')) {
                echo "PASS: phone: $phone ext: $extension<br />\n";
    } else {
        echo "FAIL: phone: $phone ext: $extension<br />\n";
    }
}

Output:

PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 0
PASS: phone: 9417516550 ext: 0
PASS: phone: 9417516550 ext: 0
PASS: phone: 9417516550 ext: 0

Upvotes: 0

Pedro Lobito
Pedro Lobito

Reputation: 98961

$pns = <<< LOL
941-751-6550 ext 2204
(941) 751-6550 ext 2204
(941)751-6550 ext 2204
9417516550 ext 2204
941-751-6550 e 2204
941-751-6550 ext 2204 
941-751-6550 extension 2204
941-751-6550 x2204
(941) 751-6550
(941)7516550
941-751-6550
941-751-6550
LOL;

preg_match_all('/^([(\d )\-]+)\s?(?:e.*?|x.*?)?(\d+)?$/sim', $pns, $matches, PREG_PATTERN_ORDER);
for ($i = 0; $i < count($matches[1]); $i++) {
    $phone = preg_replace('#[\-\(\)\s]#','', $matches[1][$i]);
    $extension = preg_replace('#[^0-9]#','', $matches[2][$i]);
    if ($phone == '9417516550' && $extension == '2204') {
             echo "PASS: phone: $phone ext: $extension\n";
    } else {
             echo "FAIL: phone: $phone ext: 0\n";
    }
}

Output:

PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
PASS: phone: 9417516550 ext: 2204
FAIL: phone: 9417516550 ext: 0
FAIL: phone: 9417516550 ext: 0
FAIL: phone: 9417516550 ext: 0
FAIL: phone: 9417516550 ext: 0

Ideone Demo

Upvotes: 0

lamp76
lamp76

Reputation: 333

This works as expected, just tested.

foreach ($tests as $test) {
    preg_match('#([\(\)0-9\-]+\s*[\(\)0-9\-]+)\s*(.*$)#',$test,$matches);
    $phone = preg_replace('#[\-\(\)\s]#','',$matches[1]);
    $extension = ($matches[2] == "") ? '0' : preg_replace('#[^0-9]#','',$matches[2]);
    if ($phone == '9417516550'
        && ($extension == '2204'
            || $extension == '0')) {
                echo "PASS: phone: $phone ext: $extension<br />\n";
    } else {
        echo "FAIL: phone: $phone ext: $extension<br />\n";
    }
}

With minimal changes on your code.

Upvotes: 1

chris85
chris85

Reputation: 23880

I'd do it all in the preg_match. Assuming the numbers are non-international I think this would work.

foreach ($tests as $test) {
    preg_match('#\(?(\d{3})\)?[-\h]?(\d{3})[-\h]?(\d{4})\h*(?:e?x?t?(?:ension)?\h(\d+))?#',$test,$matches);
    $phone = $matches[1] . $matches[2] . $matches[3];
    $extension = !empty($matches[4]) ? $matches[4] : 0;
    if ($phone == '9417516550' 
        && ($extension == '2204' || $extension == '0')) {
            echo "PASS: phone: $phone ext: $extension<br />";
    } else {
         echo "FAIL: phone: $phone ext: $extension<br />";
    }
}

Demo: https://eval.in/561720
Regex101 Demo: https://regex101.com/r/mG9iD1/1

Upvotes: 1

u_mulder
u_mulder

Reputation: 54831

(.+$) means that in the end of a line must be 1 or more symbol. So, if you have nothing after phone number - then your phone number is reduced by 1 symbol.

I advise to use (.*$) which means zero or more symbols.

Upvotes: 2

Daniel Dudas
Daniel Dudas

Reputation: 3002

From you example it looks like it fails when nothing found as ext.

A solution is to cast to int $extension like this:

$extension = intval($extension); //If nothing found will be 0

After this we are sure that we have an integer and we can change the if statement to:

|| $extension === 0)) {

Upvotes: 0

Related Questions