Regex split email address

荒凉一梦 提交于 2019-11-30 18:07:12
$parts = explode('@', "johndoe@example.com");

$user = $parts[0];
// Stick the @ back onto the domain since it was chopped off.
$domain = "@" . $parts[1];

Some of the previous answers are wrong, as a valid email address can, in fact, include more than a single @ symbol by containing it within dot delimited, quoted text. See the following example:

$email = 'a."b@c".d@e.f';
echo (filter_var($email, FILTER_VALIDATE_EMAIL) ? 'V' : 'Inv'), 'alid email format.';

Valid email format.


Multiple delimited blocks of text and a multitude of @ symbols can exist. Both of these examples are valid email addresses:

$email = 'a."b@c".d."@".e.f@g.h';
$email = '/."@@@@@@"./@a.b';

Based on Michael Berkowski's explode answer, this email address would look like this:

$email = 'a."b@c".d@e.f';
$parts = explode('@', $email);
$user = $parts[0];
$domain = '@' . $parts[1];

User: a."b"
Domain: @c".d


Anyone using this solution should beware of potential abuse. Accepting an email address based on these outputs, followed by inserting $email into a database could have negative implications.

$email = 'a."b@c".d@INSERT BAD STUFF HERE';

The contents of these functions are only accurate so long as filter_var is used for validation first.

From the left:

Here is a simple non-regex, non-exploding solution for finding the first @ that is not contained within delimited and quoted text. Nested delimited text is considered invalid based on filter_var, so finding the proper @ is a very simple search.

if(filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $a = '"';
    $b = '.';
    $c = '@';
    $d = strlen($email);
    $contained = false;
    for($i = 0; $i < $d; ++$i) {
        if($contained) {
            if($email[$i] === $a && $email[$i + 1] === $b) {
                $contained = false;
                ++$i;
            }
        }
        elseif($email[$i] === $c)
            break;
        elseif($email[$i] === $b && $email[$i + 1] === $a) {
            $contained = true;
            ++$i;
        }
    }
    $local = substr($email, 0, $i);
    $domain = substr($email, $i);
}

Here is the same code tucked inside a function.

function parse_email($email) {
    if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
    $a = '"';
    $b = '.';
    $c = '@';
    $d = strlen($email);
    $contained = false;
    for($i = 0; $i < $d; ++$i) {
        if($contained) {
            if($email[$i] === $a && $email[$i + 1] === $b) {
                $contained = false;
                ++$i;
            }
        }
        elseif($email[$i] === $c)
            break;
        elseif($email[$i] === $b && $email[$i + 1] === $a) {
            $contained = true;
            ++$i;
        }
    }
    return array('local' => substr($email, 0, $i), 'domain' => substr($email, $i));
}

In use:

$email = 'a."b@c".x."@".d.e@f.g';
$email = parse_email($email);
if($email !== false)
    print_r($email);
else
    echo 'Bad email address.';

Array ( [local] => a."b@c".x."@".d.e [domain] => @f.g )

$email = 'a."b@c".x."@".d.e@f.g@';
$email = parse_email($email);
if($email !== false)
    print_r($email);
else
    echo 'Bad email address.';

Bad email address.


From the right:

After doing some testing of filter_var and researching what is acceptable as a valid domain name (Hostnames separated by dots), I created this function to get a better performance. In a valid email address, the last @ should be the true @, as the @ symbol should never appear in the domain of a valid email address.

if(filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $domain = strrpos($email, '@');
    $local = substr($email, 0, $domain);
    $domain = substr($email, $domain);
}

As a function:

function parse_email($email) {
    if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
    $a = strrpos($email, '@');
    return array('local' => substr($email, 0, $a), 'domain' => substr($email, $a));
}

Or using explode and implode:

if(filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $local = explode('@', $email);
    $domain = '@' . array_pop($local);
    $local = implode('@', $local);
}

As a function:

function parse_email($email) {
    if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
    $email = explode('@', $email);
    $domain = '@' . array_pop($email);
    return array('local' => implode('@', $email), 'domain' => $domain);
}

Using explode is probably the best approach here, but to do it with regex you would do something like this:

/^([^@]*)(@.*)/

^ start of string

([^@]*) anything that is not an @ symbol ($matches[0])

(@.*) @ symbol followed by anything ($matches[1])

xDaizu

Answer

$parts = explode("@", $email);
$domain = array_pop($parts);
$name = implode("@",$parts);

This solves both Brogan's edge cases (a."b@c".d."@".e.f@g.hand /."@@@@@@"./@a.b) as you can see in this Ideone


The currently accepted answer is not valid because of the multiple "@" case.

I loved @Brogan's answer until I read his last sentence:

In a valid email address, the last @ should be the true @, as the @ symbol should never appear in the domain of a valid email address.

That is supported by this other answer. And if that's true, his answer seems unnecessarily complex.

If you want a preg_match solution, you could also do something like this

preg_match('/([^<]+)(@[^<]+)/','johndoe@example.com',$matches);

Use regular expression. For example:

$mailadress = "email@company.com";     
$exp_arr= preg_match_all("/(.*)@(.*)\.(.*)/",$mailadress,$newarr, PREG_SET_ORDER); 

/*
Array output:
Array
(
    [0] => Array
        (
            [0] => email@company.com
            [1] => email
            [2] => company
            [3] => com
        )

)
*/
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!