将完整的电子邮件地址拆分为姓名和电子邮件地址?

4

在原始电子邮件头的“收件人”和“发件人”字段中,似乎有许多可接受的电子邮件地址格式...

person@place.com
person <person@place.com>
person
Another Person <person@place.com>
'Another Person' <person@place.com>
"Another Person" <person@place.com>

在没有找到任何有效的PHP函数来拆分姓名和地址后,我编写了以下代码。

你可以在CODEPAD上测试以查看输出……

// 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(
    'person@place.com',
    'monarch <themonarch@tgoci.com>',
    'blahblah',
    "'doc venture' <doc@venture.com>"
    );

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

这里有什么遗漏吗?有没有更好的方法推荐?
4个回答

3

这个怎么样:

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

看起来这比正则表达式解决方案快了两倍。

注意:对于我的目的,原始帖子的第三个测试用例是不需要的。但为了回答原始帖子,我添加了if语句来产生原始帖子期望的结果。这也可以通过其他方式完成(检查$parts的最后一个元素是否为“@”)。


3

我已经成功为您的测试案例编写了一个正则表达式:

person@place.com
person <person@place.com>
person
Another Person <person@place.com>
'Another Person' <person@place.com>
"Another Person" <person@place.com>

使用这个正则表达式和preg_match函数一起使用,肯定会对你有所帮助。

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

注意:我刚刚注意到,单个“person”,即您的第三个测试用例可以通过此正则表达式丢弃(仅因为正则表达式中的空间限制),因此在您的email_split函数的第一行,在您的字符串的最后一个地方添加一个空格。
然后它会完美地达到目标。
谢谢,希望这有所帮助。
我尝试的代码:
<?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(
   'person@place.com',
   'monarch <themonarch@tgoci.com>',
   'blahblah',
   "'doc venture' <doc@venture.com>"
);

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

我得到的输出结果:

Array
(
   [name] => 
   [email] => person@place.com
)

Array
(
   [name] => monarch
   [email] => themonarch@tgoci.com
)

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

Array
(
   [name] => 'doc venture'
   [email] => doc@venture.com
)

这看起来很棒!我已经在codepad上尝试过了...http://codepad.org/TZUBdGjQ...但是出现了“未知修饰符'g'”的错误。有什么建议吗? - designosis
我已经在我的机器测试环境(PHP版本5.4.3)中尝试了我使用的代码和输出得到的结果 - 请查看编辑。 - Pritesh Tayade
很高兴我能提供一个解决方案 :) - Pritesh Tayade
1
很酷、精確的議程脚本。感謝您為此做出貢獻。我的情況是在名稱部分包含'-'字符。那麼脚本只會返回名稱的第一部分和電子郵件部分作為電子郵件。測試完整電子郵件如下:(INFO - JOSANinfo@mydomain.com) - Jothi Sankar N Kanakavel

0

在PHP中使用preg_match,http://php.net/manual/en/function.preg-match.php

或者我个人认为,您可以编写自己的函数(比如说get_email_address),它可以捕获@字符,然后从@字符获取“rest-left-string”,直到“<”字符和从@字符获取“rest-right-string”,直到“>”字符。

例如,字符串monarch <themonarch@tgoci.com>将返回“rest-left-string”=themonarch和“rest-right-string”=tgoci.com。最后,您的函数get_email_address将返回themonarch@tgoci.com

希望这有所帮助.. :)


有足够的条件和异常,似乎没有单个 preg_match 能够胜任 :( 你能想象一个包括验证的工作正则表达式吗? - designosis
是的,我明白了,在看了你的$tests变量内容后,我可以想象出来:D。那么我的第二个意见呢? - kangmasjuqi
这不是关于将john@doe.com拆分为johndoe.com的问题...而是关于从头部提取完整姓名和完整电子邮件地址的问题。 - designosis
抱歉,让您失望了:(。先来看看第一个:preg_match :) - kangmasjuqi

0

不幸的是,正则表达式在fullname的某些情况下失败了:

  • 非字母数字字符(例如“Amazon.it”)
  • 非可打印字符
  • 表情符号

我这样调整了表达式

$sPattern = '/([^<]*)?(<)?(([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/';

现在所有字符都被正确识别和分割。

已进行测试

$address = "Test User @ `` . !!  <test@email.com";

经过7年,希望这对你有所帮助 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接