使用正则表达式验证具有或不包含子域的域 - PCRE - PHP

时间:2014-04-08 16:27:57

标签: php regex pcre

我正在尝试使用最简单的正则表达式验证电子邮件地址 - 不是 - RFC‑822–compliant regex

还需要捕获用户名 - 子域名(如果有的话) - 域名和 - TLD后缀,即(com,net ....) 为此,我提出了以下正则表达式:

/^([a-z0-9_\-\.]{6,})+@((?:[a-z0-9\.])*)([a-z0-9_\-]+)[\.]([a-z0-9]{2,})$/i

例如电子邮件是:

username@domain.com
username@us.domain.com
username@au.domain.com
username@us.au.domain.com

并且正则表达式应该验证它们并捕获所有组。

所以,我想知道正则表达式是否正确或者还有什么我需要考虑的吗?

3 个答案:

答案 0 :(得分:2)

n00p,我看到你还没有找到一个表达式来完全按照自己的意愿行事,并且你说“可能有人会提出更好的解决方案并在此处发布”。

所以这是一个正则表达式,可以满足您的需求。假设你知道自己想要什么,我已经尽可能少地修改了你自己的表达式。

为了便于阅读,表达式处于自由间隔模式。你像任何其他正则表达式一样使用它。

$regex = "~(?ix) # case-insensitive, free-spacing
^                # assert head of string
([a-z0-9_-]{6,24})    # capture username to Group 1
(?<=[0-9a-z])     # assert that the previous character was a digit or letter
@                 # literal
(                 # start group 2: whole domain
(?:[a-z0-9-]+\.)* # optional subdomain: don't capture
(                 #start group 3: domain
[a-z0-9_-]+       # the last word
\.                # the dot
([a-z]{2,})       # capture TLD to group 4
)                 # end group 3: domain
)                 # end group 2: whole domain
$                 # assert end of string
~";

这将捕获组1的用户名,整个域到组2,域到组3,以及TLD到组4。

您将看到的一个小变化是我在角色类中没有转义-.,因为没有必要这样做。我没有用[a-z0-9_]替换\w表达式,因为如果您切换到unicode或其他语言环境,我们可能会得到令人惊讶的结果。

以下是使用中的全部内容:

<?php
$emails = array("username@domain.com",
           "username@us.domain.com",
           "username@au.domain.com",
           "username@us.au.domain.com");

$regex = "~(?ix) # case-insensitive, free-spacing
^                # assert head of string
([a-z0-9_-]{6,24})    # capture username to Group 1
(?<=[0-9a-z])     # assert that the previous character was a digit or letter
@                 # literal
(                 # start group 2: whole domain
(?:[a-z0-9-]+\.)* # optional subdomain: don't capture
(                 #start group 3: domain
[a-z0-9_-]+       # the last word
\.                # the dot
([a-z]{2,})       # capture TLD to group 4
)                 # end group 3: domain
)                 # end group 2: whole domain
$                 # assert end of string
~";

echo "<pre>";
foreach($emails as $email) {
    if(preg_match($regex,$email,$match)) print_r($match);
}
echo "</pre>";
?>

这是输出:

Array
(
    [0] => username@domain.com
    [1] => username
    [2] => domain.com
    [3] => domain.com
    [4] => com
)
Array
(
    [0] => username@us.domain.com
    [1] => username
    [2] => us.domain.com
    [3] => domain.com
    [4] => com
)
Array
(
    [0] => username@au.domain.com
    [1] => username
    [2] => au.domain.com
    [3] => domain.com
    [4] => com
)
Array
(
    [0] => username@us.au.domain.com
    [1] => username
    [2] => us.au.domain.com
    [3] => domain.com
    [4] => com
)

答案 1 :(得分:1)

最有可能的是,您最好使用parse_url来获取零件,然后针对不同的零件进行任何类型的验证

答案 2 :(得分:0)

我已经尝试了一段时间,但我仍然没有得到最合适的结果,但这是我到目前为止最接近的结果:

^([a-z0-9_\-\.]{6,24})(?<=[0-9a-z])@((?:[a-z0-9][-\w]*[a-z0-9]*\.)+([a-z]{2,}))$

这将捕获用户名,TLD后缀和整个域,以及验证包含或不包含子域的电子邮件。但我仍然无法提取域名。我想我现在可以忍受。

对于诸如username@domain.com之类的电子邮件,它将验证并捕获用户名,domain.com和com以及其他电子邮件,例如username@au.domain.com,它将验证并捕获用户名,au.domain.com和com

这不完全不是我想要的,可能会有人会提出更好的解决方案并在此发布。