到目前为止,我已经有了这个:
preg_match('/<?([^<]+?)@/', 'johndoe@example.com', $matches);
,并且我得到了Array ( [0] => johndoe@ [1] => johndoe)
。那么我需要如何改变正则表达式?
preg_match('/<?([^<]+?)@/', 'johndoe@example.com', $matches);
,并且我得到了Array ( [0] => johndoe@ [1] => johndoe)
。$parts = explode('@', "johndoe@example.com");
$user = $parts[0];
// Stick the @ back onto the domain since it was chopped off.
$domain = "@" . $parts[1];
list($name,$_) = explode('@',$email); $domain = '@'.$_;
- http://www.ideone.com/yHlz6 - Brad Christie$_
。无论好坏与否(并冒着可读性的风险),它都可以更快地编写变量。而且,在我的记事本获得 PHP 编码的智能感知之前,我可能会继续这样做。;p - Brad Christie之前的一些回答是错误的,因为一个有效的电子邮件地址实际上可以包含不止一个@符号,方法是在带引号的点分隔文本中包含它。请看以下示例:
$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';
$email = 'a."b@c".d@e.f';
$parts = explode('@', $email);
$user = $parts[0];
$domain = '@' . $parts[1];
用户:a."b"
域名:@c".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.';
$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 进行一些测试并研究什么是有效的域名(由点分隔的主机名)后,我创建了这个函数以获得更好的性能。在有效的电子邮件地址中,最后一个 @ 应该是真正的 @,因为 @ 符号不应出现在有效电子邮件地址的域中。
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));
}
或者使用explode和implode函数:
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);
}
/(.*)(@.*)$/
(.*) 可以匹配任何内容。
(@.*) 可以匹配以@符号开头的任何内容。
$ 表示字符串的结尾。
if(filter_var($email, FILTER_VALIDATE_EMAIL)) {
$local = preg_split('/(.*)(@.*)$/', $email, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$domain = $local[1];
$local = $local[0];
}
作为一个函数:
function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
$email = preg_split('/(.*)(@.*)$/', $email, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
return array('local' => $email[0], 'domain' => $email[1]);
}
或者
if(filter_var($email, FILTER_VALIDATE_EMAIL)) {
preg_match('/(.*)(@.*)$/', $email, $matches);
$local = $matches[1];
$domain = $matches[2];
}
作为一个函数:
function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
preg_match('/(.*)(@.*)$/', $email, $matches);
return array('local' => $matches[1], 'domain' => $matches[2]);
}
/^([^@]*)(@.*)/
^ 字符串的开头
([^@]*) 除了@符号以外的所有内容($matches[0])
(@.*) @符号后面的任何东西($matches[1])
$parts = explode("@", $email);
$domain = array_pop($parts);
$name = implode("@",$parts);
这解决了Brogan的两个边界情况(a."b@c".d."@".e.f@g.h
和/."@@@@@@"./@a.b
),你可以在这个Ideone链接中看到。
目前被接受的答案不正确,因为它无法处理多个 "@" 的情况。
我很喜欢@Brogan的答案,但最后一句话让我失望:
在有效的电子邮件地址中,最后的@应该是真正的@,因为@符号永远不应出现在有效电子邮件地址的域中。
这个答案支持这种说法。如果这是真的,他的答案似乎过于复杂了。
$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
)
)
*/
@@@@@@@@@.
是无效的,但是 me@localhost
是有效的。 - Totopreg_match('/([^<]+)(@[^<]+)/','johndoe@example.com',$matches);
正则表达式:
(?<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:域部分也基于 域 RFC 而非仅基于 2822。
危险字符: 我明确包括了 '$!
等字符,既是为了明确这些字符受到 电邮 RFC 批准,也是为了方便删除特定字符集(例如阻止可能的 SQL 注入攻击)应该在您的系统中被禁止。
无法逃脱:对于邮箱名称,我仅包含点-原子格式,有意地排除了点或斜杠转义支持。
微妙的字母:对于某些部分,我使用了[^\W\d_]而不是[a-zA-Z],以提高对英语以外语言的支持。
越界:由于某些系统中捕获组处理的特殊性,我使用+
代替{,61}
。如果您在某个可能受到缓冲区溢出攻击的地方使用它,请记得限制您的输入。
致谢:修改自Tripleaxis社区帖子,该帖子又取自.net帮助文件。
'$!
感到困惑。我已经更新了答案,以更清楚地解释它们的存在。如果您发现它有用,请随意查看并评价自己。 - Chris Rudd
$domain = substr($email, strrpos($email, '@')+1);
- Kamil Kiełczewski