【问题标题】:Parse RFC 822 compliant addresses in a TO header在 TO 标头中解析符合 RFC 822 的地址
【发布时间】:2011-09-30 08:28:22
【问题描述】:

我想用 preg_match_all 解析一个电子邮件地址列表(如 TO 标头中的那个),以获取用户名(如果存在)和电子邮件。类似于 Pear 中的 mailparse_rfc822_parse_addresses 或 Mail_RFC822::parseAddressList() 的东西,但使用纯 PHP。

输入:

"DOE, John \(ACME\)" <john.doe@somewhere.com>, "DOE, Jane" <jane.doe@somewhere.com>

输出:

array(
    array(
        'name' => 'DOE, John (ACME)',
        'email' => 'john.doe@somewhere.com'
    ), 
    array(
        'name' => 'DOE, Jane',
        'email' => 'jane.doe@somewhere.com'
    )
)

不需要支持奇怪的E-mail格式(/[a-z0-9._%-]+@[a-z0-9.-]+.[az]{2,4}/i电子邮件部分可以)。

我不能使用explode,因为逗号可以出现在名称中。 str_getcsv 不起作用,因为我可以:

DOE, John \(ACME\) <john.doe@somewhere.com> 

作为输入。

更新:

目前,我有这个:

public static function parseAddressList($addressList)
{
    $pattern = '/^(?:"?([^<"]+)"?\s)?<?([^>]+@[^>]+)>?$/';
    if (preg_match($pattern, $addressList, $matches)) {
        return array(
            array(
                'name' => stripcslashes($matches[1]),
                'email' => $matches[2]
            )
        );
    } else {
        $parts = str_getcsv($addressList);
        $result = array();
        foreach($parts as $part) {
            if (preg_match($pattern, $part, $matches)) {
                $result[] = array(
                    'name' => stripcslashes($matches[1]),
                    'email' => $matches[2]
                );
            }
        }
        return $result;
    }
}

但它失败了:

"DOE, \"John\"" <john.doe@somewhere.com>

我需要测试反向引用 \" 但我不记得如何做到这一点。

【问题讨论】:

    标签: php regex


    【解决方案1】:

    我不知道那个 RFC,但如果格式始终如您所见,那么您可以尝试以下方法:

    preg_match_all("/\"([^\"]*)\"\\s+<([^<>]*)>/", $string, $matches);
    print_r($matches);
    

    【讨论】:

    • 不起作用,因为双引号不是强制性的。不过还是谢谢啦。
    【解决方案2】:

    我终于做到了:

    public static function parseAddressList($addressList)
    {
        $pattern = '/^(?:"?((?:[^"\\\\]|\\\\.)+)"?\s)?<?([a-z0-9._%-]+@[a-z0-9.-]+\\.[a-z]{2,4})>?$/i';
        if (($addressList[0] != '<') and preg_match($pattern, $addressList, $matches)) {
            return array(
                array(
                    'name' => stripcslashes($matches[1]),
                    'email' => $matches[2]
                )
            );
        } else {
            $parts = str_getcsv($addressList);
            $result = array();
            foreach($parts as $part) {
                if (preg_match($pattern, $part, $matches)) {
                    $item = array();
                    if ($matches[1] != '') $item['name'] = stripcslashes($matches[1]);
                    $item['email'] =  $matches[2];
                    $result[] = $item;
                }
            }
            return $result;
        }
    }
    

    但我不确定它是否适用于所有情况。

    【讨论】:

    • 这个正则表达式给我带来了一些问题,如果电子邮件地址在@之前有一个 -,这为我修复了它(即转义正则表达式中的 -)$pattern = '/^(?:"?((?:[^"\\\\]|\\\\.)+)"?\s)?&lt;?([a-z0-9._%\-+]+@[a-z0-9.\-]+\\.[a-z]{2,10})&gt;?$/i';
    • 由于没有名称部分的普通旧电子邮件地址也会失败...需要 trim() 每个“部分”Bob &lt;bob@test.com&gt;, notparsed@sad.com 每个 $part 需要修剪,因为前导空格
    猜你喜欢
    • 2013-05-22
    • 2010-12-23
    • 2014-10-11
    • 2013-09-04
    • 2013-09-01
    • 1970-01-01
    • 2015-12-12
    • 2017-11-05
    • 2011-05-12
    相关资源
    最近更新 更多