Во-первых, хорошая работа по предоставлению комментариев для вашего регулярного выражения. Тем не менее, есть гораздо лучший способ. Просто напишите свое регулярное выражение с самого начала в режиме свободного пробела с большим количеством комментариев. Таким образом, вы можете документировать свое регулярное выражение прямо в исходном коде (и предоставлять отступы для улучшения читабельности при большом количестве скобок). Вот как бы я написал ваше оригинальное регулярное выражение в коде C #:
if (Regex.IsMatch(usernameString,
@"# Validate username having a digit and/or special char.
^ # Either... Anchor to start of string.
(?=.*\d) # Assert there is a digit AND
(?=.*[A-Za-z]) # assert there is an alpha.
.{6-12} # Match any name with length from 6 to 12.
$ # Anchor to end of string.
| ^ # Or... Anchor to start of string
(?=.*[A-Za-z]) # Assert there is an alpha AND
(?=.* # assert there is either a special char
[!#$%&'\(\)\*\+-\.:;<=>\?@\[\\\]\^_`\{\|\}~\x22]
| .*\s # or a space char.
) # End specialchar-or-space assertion.
.{6-12} # Match any name with length from 6 to 12.
$ # Anchor to end of string.
", RegexOptions.IgnorePatternWhitespace)) {
// Valid username.
} else {
// Invalid username.
}
В приведенном выше фрагменте кода используется предпочтительный синтаксис строки @"..."
, который упрощает экранирование метасимволов. Это оригинальное регулярное выражение ошибочно разделяет два числа квантификатора фигурных скобок, используя тире, то есть .{6-12}
. Правильный синтаксис - разделять эти числа запятыми, т.е. .*{6,12}
. (Может быть .NET позволяет использовать синтаксис .{6-12}
?) Я также изменил 0x0022
(символ "
в двойных кавычках) на \x22
.
Тем не менее, да, оригинальное регулярное выражение можно немного улучшить:
if (Regex.IsMatch(usernameString,
@"# Validate username having a digit and/or special char.
^ # Anchor to start of string.
(?=.*?[A-Za-z]) # Assert there is an alpha.
(?: # Group for assertion alternatives.
(?=.*?\d) # Either assert there is a digit
| # or assert there is a special char
(?=.*?[!#$%&'()*+-.:;<=>?@[\\\]^_`{|}~\x22\s]) # or space.
) # End group of assertion alternatives.
.{6,12} # Match any name with length from 6 to 12.
$ # Anchor to end of string.
", RegexOptions.IgnorePatternWhitespace)) {
// Valid username.
} else {
// Invalid username.
}
Это регулярное выражение исключает глобальную альтернативу и вместо этого использует группу без захвата для "цифр или спецсимволов" альтернативных утверждений. Кроме того, вы можете исключить группу без захвата для «специальных символов или пробелов» , просто добавив \s
в список специальных символов. Я также добавил ленивый модификатор к точечным звездам в утверждениях, то есть .*?
- (это может сделать совпадение с регулярным выражением немного быстрее.) Куча ненужных выходов была удалена из класса символов specialchar.
Но, как умно указала Stema, вы можете комбинировать цифру и специальный символ, чтобы еще больше упростить это:
if (Regex.IsMatch(usernameString,
@"# Validate username having a digit and/or special char.
^ # Anchor to start of string
(?=.*?[A-Za-z]) # Assert there is an alpha.
# Assert there is a special char, space
(?=.*?[!#$%&'()*+-.:;<=>?@[\\\]^_`{|}~\x22\s\d]) # or digit.
.{6,12} # Match any name with length from 6 to 12.
$ # Anchor to end of string.
", RegexOptions.IgnorePatternWhitespace)) {
// Valid username.
} else {
// Invalid username.
}
Кроме этого, в вашем исходном регулярном выражении нет ничего плохого в том, что касается точности. Однако, по логике, эта формула позволяет имени пользователя заканчиваться пробелом, что, вероятно, не очень хорошая идея. Я бы также явно указывал в имени белый список допустимых символов, а не использовал бы чрезмерно разрешающую "."
точку.