这是我在这里的第一个问题。目前我正在开发一个 PHP 论坛脚本,我想让人们注册一个遵守我规则的用户名。
规则很简单:
- 第一个字符必须是字母
- 他们也可以使用数字,但这不是第一个
- 他们可以使用一次句号/下划线,但不能在用户名末尾使用
请帮助我放下一个功能。我阅读了一些教程,但不太了解正则表达式。出于这个原因,我被困住了。提前感谢您的回答。
20 分钟后添加:
感谢您的回答,我还有一件事要问,我可以解除愚蠢的用户名吗?EG aaa123, ab-cd,uuuu ...比怎么样?
拿你描述的部分:
- 第一个字符必须是字母
开始^[A-Za-z]
- 他们也可以使用数字,但这不是第一个
[A-Za-z0-9]*
在中间
- 他们可以使用一次句号/下划线,但不能在用户名末尾使用
(可选)有一个下划线,后跟至少一个其他有效字符([._][A-Za-z]+)?
把它们放在一起,你就有了:/^[A-Za-z][A-Za-z0-9]*([._][A-Za-z0-9]+)?$/
. 使用不区分大小写 '/i' 的标志可以让您删除 'AZ': /^[a-z][a-z0-9]*([._][a-z0-9]+)?$/i
。
正则表达式等价于确定性有限自动机(DFA)。研究它们可以帮助掌握正则表达式。特别是状态之间的转换,直接适用于你的三点。这种语言的(简化的)状态图应该很容易理解:
外交部:
我称它为“减少”,因为有第五个不接受状态和未显示的导致它的边缘。基本上,如果遇到的字符不是列出的字符,DFA 就会转换到第五个不接受状态并停留在那里。
将preg_match与正则表达式一起使用^[a-z][a-z0-9]*([._][a-z0-9]+)?$
:
$regex = '/^[a-z][a-z0-9]*([._][a-z0-9]+)?$/i';
echo preg_match($regex, 'valid_user1'); # => 1
echo preg_match($regex, 'Valid_user1'); # => 1
echo preg_match($regex, '0invalid_user'); # => 0
echo preg_match($regex, 'invaliduser_'); # => 0
echo preg_match($regex, 'in_valid_user'); # => 0
更新
正则表达式来自 outis 的回答。
以下模式允许 4 到 12 个字符的用户名,第一个字符为字母,只有一个点和一个下划线:
$pattern = '~^(?=.{4,12}$)[a-z]++[^\W_]*+(_[^\W_]++)?+(?>\.[^\W_]++)?+(?(1)|(_[^\W_]++)?+)$~i';
您可以将它与 preg_match 一起使用来检查用户名。
图案细节:
~ # pattern delimiter
^ # begining anchor
(?=.{4,12}$) # lookahead assertion: check if the length is between 4 and 12
# characters. It stand for: "followed by between 4 and 12 chars
# and the end of the string
[a-z]++ # one or more letters
[^\W_]*+ # zero or more letters or digits. Since ^ means that the character
# class is negated, _ is excluded with all that is not a part of \w
(_[^\W_]++)?+ # first capturing group with an underscore and one or more
# letters/digits. The group is optional
(?>\.[^\W_]++)?+ # a non capturing group with a dot (optional too)
(?(1) # conditional: if the first capturing group exist there is nothing
| # OR
(_[^\W_]++)?+ # you can have an underscore here (optional)
)
$ # anchor: end of the string
~ # pattern delimiter
i # case insensitive modifier
关于“愚蠢的用户名”,除了编写“黑名单”并在之后(或在具有前瞻或后视的模式中)检查用户名之外,您无能为力,但我不确定这是否非常有用,因为它不是密码。
我知道你要求一个正则表达式,但也许我可以说服你,它可以很容易地用老式的方式完成:
function validUsername($user) {
// A few variables
$minlen = 3;
$maxlen = 20;
$usrlen = strlen($user);
// Allowed length of username
if ($usrlen < $minlen || $usrlen > $maxlen) {
return false;
}
// First character must be alpha
if ( ! ctype_alpha($user[0])) {
return false;
}
// Last letter cannot be . or _ which means
// that it must be alphanum
if ( ! ctype_alnum($user[$usrlen-1])) {
return false;
}
// Go over each character, excluding the first
// and last, because we have already dealt with them
for ($i = 1; $i < $usrlen-1; $i++) {
// Grab the currect character
$char = $user[$i];
// If it is alphanum then it is valid
if (ctype_alnum($char)) {
continue;
}
// Dots and underscores cannot appear in pairs
elseif ($char === '.' || $char === '_') {
if ($user[$i-1] === $char || $user[$i+1] === $char) {
return false;
}
}
// Character not supported
else return false;
}
// Everything seems to be in order
return true;
}