我需要一些帮助php regex,我想"拆分"电子邮件地址"johndoe@example.com"到"johndoe"answers"@example.com"
直到现在我有这个: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];
前面的一些答案是错误的,因为一个有效的电子邮件地址实际上可以包含多个@符号,通过将其包含在点分隔的引号文本中。请看下面的例子:
$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。"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.';
Array ([local] => a."b@c".x."@".d。E[域]=> @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进行了一些测试并研究了什么是可接受的有效域名(主机名以点分隔)之后,我创建了这个函数以获得更好的性能。在一个有效的电子邮件地址中,最后一个@应该是真正的@,因为@符号不应该出现在一个有效的电子邮件地址的域中。
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));
}
或者使用explosion and 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]);
}
使用爆炸可能是这里最好的方法,但要使用regex,您将做这样的事情:
/^([^@]*)(@.*)/
^ string
([^@]*)的东西不是一个@符号($ matches [0])
(@ *)。 @符号紧随其后的是什么($ matches [1])
回答$parts = explode("@", $email);
$domain = array_pop($parts);
$name = implode("@",$parts);
$parts = explode("@", $email);
$domain = array_pop($parts);
$name = implode("@",$parts);
这解决了Brogan的边界情况(a."b@c".d."@".e.f@g.h
和/."@@@@@@"./@a.b
),你可以在这个Ideone
由于多个"@"大小写,当前接受的答案无效。
我很喜欢@Brogan的回答,直到我读到他的最后一句话:
在一个有效的电子邮件地址中,最后一个@应该是真正的@,因为@符号不应该出现在一个有效的电子邮件地址的域中。
得到另一个答案的支持。如果这是真的,他的回答似乎没有必要那么复杂。
如果需要preg_match解决方案,还可以这样做
preg_match('/([^<]+)(@[^<]+)/','johndoe@example.com',$matches);
使用正则表达式。例如:
$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
)
)
*/
我已经为此创建了一个通用正则表达式,用于验证和创建完整电子邮件、用户和域的命名捕获。
正则表达式:
(?<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拆分电子邮件地址"找到它。
特性兼容性:不是所有的regex处理器都支持命名捕获,如果你在Regexr上遇到麻烦,用你的文本测试它(检查细节以查看捕获)。如果它在那里工作,然后仔细检查你正在使用的regex引擎是否支持命名捕获。
域RFC:域部分也基于域RFC而不仅仅是2822
危险字符:我已经明确地包含了'$!
等,以明确这些是邮件RFC允许的,并且如果由于特殊的处理要求(如阻止可能的sql注入攻击),在您的系统中不允许一组特定的字符,则可以轻松删除
No Escape:对于邮箱名我只包含了点原子格式,我故意排除了点或斜杠转义支持
微妙的字母:对于某些部分,我使用[^'W'd_]而不是[a-zA-Z]来提高对英语以外语言的支持。
越界:由于某些系统中捕获组处理的特殊性,我使用+
代替{,61}
。如果您在容易受到缓冲区溢出攻击的地方使用它,请记住绑定输入
credit:从Tripleaxis的社区帖子修改,这是反过来从。net帮助文件