正则表达式拆分电子邮件地址

时间:2011-07-27 20:36:11

标签: php regex email preg-match

我需要一些关于php regex的帮助,我想将“johndoe@example.com”的电子邮件地址“拆分”为“johndoe”和“@ example.com”

到现在为止,我有这个:preg_match('/<?([^<]+?)@/', 'johndoe@example.com', $matches); 我得到Array ( [0] => johndoe@ [1] => johndoe)

那么我需要如何更改正则表达式?

7 个答案:

答案 0 :(得分:26)

$parts = explode('@', "johndoe@example.com");

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

答案 1 :(得分:7)

之前的一些答案是错误的,因为有效的电子邮件地址实际上可以包含多个@符号,方法是在点分隔的引用文本中包含它。请参阅以下示例:

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

有效的电子邮件格式。


可以存在多个分隔的文本块和多个@符号。这两个示例都是有效的电子邮件地址:

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

根据Michael Berkowski的爆炸答案,此电子邮件地址如下所示:

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

用户:a。&#34; b&#34;
  域名:@ c&#34; .d


使用此解决方案的任何人都应该注意潜在的滥用接受基于这些输出的电子邮件地址,然后将$ email插入数据库可能会产生负面影响。

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

只要filter_var首先用于验证,这些函数的内容才是准确的。

从左边开始:

这是一个简单的非正则,非爆炸性解决方案,用于查找未包含在分隔和引用文本中的第一个@。基于filter_var,嵌套分隔文本被视为无效,因此找到正确的@是一个非常简单的搜索。

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

这是隐藏在函数内的相同代码。

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

使用中:

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

数组([local] =&gt; a。&#34; b @ c&#34; .x。&#34; @&#34; .d.e [domain] =&gt; @ 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.';
  

电子邮件地址错误。

从右边开始:

在对filter_var进行一些测试并研究可接受的有效域名(Hostnames以点分隔)后,我创建了此函数以获得更好的性能。在有效的电子邮件地址中,最后一个@应该是真@,因为@符号永远不会出现在有效电子邮件地址的域中。

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

作为一项功能:

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

或使用爆炸和内爆:

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

作为一项功能:

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

答案 2 :(得分:3)

使用explode可能是最好的方法,但要使用正则表达式,你可以这样做:

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

^ 字符串的开头

([^ @] *)任何不是@符号的内容($ matches [0])

(@。*) @符号后跟任何内容($ matches [1])

答案 3 :(得分:1)

答案

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

这解决了Brogan的边缘情况(a."b@c".d."@".e.f@g.h/."@@@@@@"./@a.b),您可以在this Ideone

中看到

由于多个&#34; @&#34; currently accepted answer无效。情况下。

我爱@Brogan's answer直到我读完他的最后一句话:

  

在有效的电子邮件地址中,最后一个@应该是真@,因为@符号永远不会出现在有效电子邮件地址的域中。

this other answer支持。如果这是真的,他的回答似乎不必要地复杂。

答案 4 :(得分:0)

如果你想要一个preg_match解决方案,你也可以做这样的事情

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

答案 5 :(得分:-1)

使用正则表达式。例如:

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

)
*/

答案 6 :(得分:-1)

我为此创建了一个通用的正则表达式 validates 并创建了完整电子邮件、用户和域的命名捕获。

正则表达式:

(?<email>(?<mailbox>(?:\w|[!#$%&'*+/=?^`{|}~-])+(?:\.(?:\w|[!#$%&'*+/=?^`{|}~-])+)*)@(?<full_domain>(?<subdomains>(?:(?:[^\W\d_](?:(?:[^\W_]|-)+[^\W_])?)\.)*)(?<root_domain>[^\W\d_](?:(?:[^\W_]|-)+[^\W_])?)\.(?<tld>[^\W\d_](?:(?:[^\W_]|-)+[^\W_])?)))

说明:

(?<email>                          #  start Full Email capture
  (?<mailbox>                      #    Mailbox
    (?:\w|[!#$%&'*+/=?^`{|}~-])+   #      letter, number, underscore, or any of these special characters
    (?:                            #      Group: allow . in the middle of mailbox; can have multiple but can't be consecutive (no john..smith)
      \.                           #        match "." 
      (?:\w|[!#$%&'*+/=?^`{|}~-])+ #        letter, number, underscore, or any of these special characters
    )*                             #      allow one letter mailboxes
  )                                #    close Mailbox capture
  @                                #    match "@"
  (?<full_domain>                  #    Full Domain (including subdomains and tld)
    (?<subdomains>                 #      All Subdomains
      (?:                          #        label + '.' (so we can allow 0 or more)
        (?:                        #          label text
          [^\W\d_]                 #            start with a letter (\W is the inverse of \w so we end up with \w minus numbers and _)
          (?:                      #            paired with a ? to allow single letter domains
            (?:[^\W_]|-)+          #              allow letters, numbers, hyphens, but not underscore
            [^\W_]                 #              if domain is more than one character, it has to end with a letter or digit (not a hyphen or underscore)
          )?                       #            allow one letter sub domains
        )                          #          end label text
      \.)*                         #        allow 0 or more subdomains separated by '.'
    )                              #      close All Subdomains capture
    (?<root_domain>                #      Root Domain
      [^\W\d_]                     #        start with a letter
      (?:                          #        paired with ? to make characters after the first optional
        (?:[^\W_]|-)+              #          allow letters, numbers, hyphens
        [^\W_]                     #          if domain is more than one character, it has to end with a letter or digit (not a hyphen or underscore)
      )?                           #        allow one letter domains
    )                              #      close Root Domain capture
    \.                             #      separator
    (?<tld>                        #      TLD
      [^\W\d_]                     #        start with a letter
      (?:                          #        paired with ? to make characters after the first optional
        (?:[^\W_]|-)+              #          allow letters, numbers, hyphens
        [^\W_]                     #          if domain is more than one character, it has to end with a letter or digit (not a hyphen)
      )?                           #        allow single letter tld
    )                              #      close TLD capture
  )                                #    close Full Domain capture
)                                  #  close Full Email capture

注意事项

通用正则表达式:我只发布了正则表达式搜索本身,而不是 php 专有的东西。这是为了让其他根据名称“Regex Split Email Address”找到它的人更容易使用。

功能兼容性:并非所有正则表达式处理器都支持命名捕获,如果您遇到问题,请使用 Regexr 上的文本对其进行测试(检查详细信息以查看捕获)。如果它在那里工作,请仔细检查您使用的正则表达式引擎是否支持命名捕获。

域 RFC:域部分也基于 domain RFC 而不仅仅是 2822

危险字符:我已经明确地包含了 '$! 等,以明确mail RFC 允许这些并使其变得容易删除是否由于特殊处理要求(例如阻止可能的 sql 注入攻击)而在您的系统中禁止使用特定字符集

无转义:对于邮箱名称,我只包含点原子格式,我有意排除了点或斜线转义支持

微妙的字母:对于某些部分,我使用 [^\W\d_] 而不是 [a-zA-Z] 来改进对英语以外语言的支持。

越界:由于某些系统中捕获组处理的特殊性,我使用 + 代替 {,61}。如果您在可能容易受到缓冲区溢出攻击的地方使用它,请记住 bound your inputs

致谢:由 Tripleaxis 修改自社区帖子,该帖子又取自 .net 帮助文件