从字符串中获取完整的电子邮件地址

14

我目前正在使用Laravel构建Slack机器人,其中一个功能是它可以接收电子邮件地址并向其发送消息。

问题在于,来自Slack的电子邮件地址(例如bob@example.com)以<mailto:bob@example.com|bob@example.com>的形式出现。

我目前有一个从中获取电子邮件的函数:

public function getEmail($string)
{
    $pattern = '/[a-z0-9_\-\+]+@[a-z0-9\-]+\.([a-z]{2,3})(?:\.[a-z]{2})?/i';
    preg_match_all($pattern, $string, $matches);
    $matches = array_filter($matches);

    return $matches[0][0];
}

这似乎对于像bob@example.com这样的电子邮件地址有效,但是在处理像bob.jones@example.com这样的电子邮件地址时似乎会出现错误(会被转换为<mailto:bob.jones@example.com|bob.jones@example.com>)。在这些情况下,该函数返回jones@example.com作为电子邮件地址。

我不太擅长正则表达式,但是是否有其他我可以使用/更改的模式,或者从Slack提供的字符串中提取电子邮件地址的更好方法?


如果str总是这样的,也可以尝试preg_match('/mailto:\K[^|>]+/', $str, $out) - bobble bubble
3个回答

10

如果你知道格式始终如此,那么总是可以将正则表达式从方程中删除:

$testString = '<mailto:bob@example.com|bob@example.com>';

$testString = str_replace(['<mailto:', '>'], '', $testString);

$addresses = explode('|', $testString);

echo $addresses[0];

2
并在下面添加验证:`foreach ($addresses as $value) {if (filter_var($value, FILTER_VALIDATE_EMAIL)) { echo "有效的电子邮件地址: " . $value . "
"; }
}`
- Kitson88
4
这个,再加上@Kitson88的微小调整,完美解决了。感谢你们两个! - James
@bcmcfc,看起来你精通Laravel。我需要你的帮助。请看这里:http://stackoverflow.com/questions/41887504/how-to-solve-missing-argument-1-for-app-repositories-favoriterepositorydelete/41887543 - moses toh

4

这种方法可以完成任务,而且避免了使用常规表达式。通过使用php函数对电子邮件地址进行验证,确保返回的电子邮件是真实的。

function getEmailAddress($string) 
{
    $string = trim($string, '<>');
    $args = explode('|', $string);
    foreach ($args as $_ => $val) {
        if(filter_var($val, FILTER_VALIDATE_EMAIL) !== false) {
            return $val;
        }
    }

    return null;    
}

echo getEmailAddress('<mailto:bob@example.com|bob@example.com>');

输出

bob@example.com

0

您知道包含电子邮件地址的字符串将始终采用以下形式:<mailto:bob@example.com|bob@example.com>,因此请使用该格式。具体来说,您知道该字符串将以<mailto:开头,将包含一个|,并以>结尾。

然而,一个额外的困难是,电子邮件地址的本地部分也可能包含管道字符,但域名不会;请参见以下问题。
电子邮件地址允许使用哪些字符?

public function getEmail($string)
{
    $pattern = '/^<mailto:([^@]+@[^|]+)|(.*)>$/i';
    preg_match_all($pattern, $string, $matches);
    $matches = array_filter($matches);
    return $matches[1][0];
}

这将从开头到结尾匹配整行内容,但我们会在第一组括号中捕获电子邮件地址。 $matches[1] 包含第一个捕获括号内的所有匹配项。你也可以使用 preg_match,因为你不是在寻找所有匹配项,而只是第一个。


+1 从来不知道电子邮件可以包含一个管道符号。虽然听起来很疯狂,但想象一下试图通过电话向某人解释你的电子邮件包含一个管道字符。有时候让人理解个人域名已经够难了!出于好奇,我刚刚测试了Gmail,他们只支持规范的子集:“请仅使用字母(a-z)、数字和句点。” - bcmcfc
@bcmcfc 每个域名都可以设置自己的规则,只要不违反规范。但是他们不必实现完整的规范。换句话说,GMail不必允许 bc|mc|fc@gmail.com,但他们应该允许发送电子邮件到 {bc|mc|fc}$@someotherdomain.com - SQB
@SQB,看起来你掌握了 Laravel。我需要你的帮助。看这里:http://stackoverflow.com/questions/41047583/how-to-add-dynamic-dropdown-list-column-on-laravel-5-3-registration - moses toh

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