Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

split full email addresses into name and email?

There seems to be many acceptable email address formats in the To: and From: raw email headers ...

[email protected]
person <[email protected]>
person
Another Person <[email protected]>
'Another Person' <[email protected]>
"Another Person" <[email protected]>

After not finding any effective PHP functions for splitting out names and addresses, I've written the following code.

You can DEMO IT ON CODEPAD to see the output...

// validate email address
function validate_email( $email ){
    return (filter_var($email, FILTER_VALIDATE_EMAIL)) ? true : false;
}

// split email into name / address
function email_split( $str ){
    $name = $email = '';
    if (substr($str,0,1)=='<') {
        // first character = <
        $email = str_replace( array('<','>'), '', $str );
    } else if (strpos($str,' <') !== false) {
        // possibly = name <email>
        list($name,$email) = explode(' <',$str);
        $email = str_replace('>','',$email);
        if (!validate_email($email)) $email = '';
        $name = str_replace(array('"',"'"),'',$name);
    } else if (validate_email($str)) {
        // just the email
        $email = $str;
    } else {
        // unknown
        $name = $str;
    }
    return array( 'name'=>trim($name), 'email'=>trim($email) );
}

// test it
$tests = array(
    '[email protected]',
    'monarch <[email protected]>',
    'blahblah',
    "'doc venture' <[email protected]>"
    );

foreach ($tests as $test){
    echo print_r( email_split($test), true );
}

Am I missing anything here? Can anyone recommend a better way?

like image 579
neokio Avatar asked Sep 06 '25 03:09

neokio


2 Answers

I have managed to make one regex to your test cases:

[email protected]
person <[email protected]>
person
Another Person <[email protected]>
'Another Person' <[email protected]>
"Another Person" <[email protected]>

using preg_match with this regex will surely help you bit.

function email_split( $str ){
$sPattern = "/([\w\s\'\"]+[\s]+)?(<)?(([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/g";
preg_match($sPattern,$str,$aMatch);

if(isset($aMatch[1]))
{
echo $aMatch[1] //this is name;
}

if(isset($aMatch[3]))
{
echo $aMatch[3] //this is EmailAddress;
}
}

Note: I just noticed that single "person" i.e. your third test case could be discarded with this regex (just that because of space constraint in regex) so,at first line of your email_split function, append space at last place of your string.

Then it would be bang on target.

Thanks, Hope this helps.

Code I tried:

<?php

// validate email address
function validate_email($email) {
   return (filter_var($email, FILTER_VALIDATE_EMAIL)) ? true : false;
}

// split email into name / address
function email_split($str) {
   $str .=" ";
   $sPattern = '/([\w\s\'\"]+[\s]+)?(<)?(([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/';
   preg_match($sPattern, $str, $aMatch);
   //echo "string";
   //print_r($aMatch);
   $name = (isset($aMatch[1])) ? $aMatch[1] : '';
   $email = (isset($aMatch[3])) ? $aMatch[3] : '';
   return array('name' => trim($name), 'email' => trim($email));
}

// test it
$tests = array(
   '[email protected]',
   'monarch <[email protected]>',
   'blahblah',
   "'doc venture' <[email protected]>"
);

foreach ($tests as $test) {
   echo "<pre>";
   echo print_r(email_split($test), true);
   echo "</pre>";
}

Output I got:

Array
(
   [name] => 
   [email] => [email protected]
)

Array
(
   [name] => monarch
   [email] => [email protected]
)

Array
(
   [name] => blahblah
   [email] => 
)

Array
(
   [name] => 'doc venture'
   [email] => [email protected]
)
like image 77
Pritesh Tayade Avatar answered Sep 07 '25 20:09

Pritesh Tayade


How about this:

function email_split($str) {
    $parts = explode(' ', trim($str));
    $email = trim(array_pop($parts), "<> \t\n\r\0\x0B");
    $name = trim(implode(' ', $parts), "\"\' \t\n\r\0\x0B");
    if ($name == "" && strpos($email, "@") === false) {             // only single string - did not contain '@'
        $name = $email;
        $email = "";
    }
    return array('name' => $name, 'email' => $email);
}

Looks like this is about twice as fast as the regex solution.

Note: the OPs third test case (for my purposes) is not needed. But in the interest of answering the OP I added the if stmt to produce the OPs expected results. This could have been done other ways (check the last element of $parts for '@').

like image 32
ds00424 Avatar answered Sep 07 '25 20:09

ds00424