优化用户名验证正则表达式的前瞻性



我想用以下规则验证用户名:

  • 只能使用字符a-zA-Z0-9_.-
  • 字符_.-不能是第一个或最后一个字符
  • 字符_.-不能相邻(符号之间必须至少有一个字母或数字字符)
  • 长度必须在3到15个字符之间,不包括任何_, .-字符(必须有3-15个字母数字字符)

此时我使用以下正则表达式(点击查看):

/^(?=([A-Za-z0-9][-._]?){3,15}$)[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/

关于如何优化这个,特别是展望有什么想法吗?我试着向前看的(?=[^-._]{3,15}),但它似乎没有工作。注意,我只能使用javascript兼容的regex。

有些人在遇到问题时,会想"我知道,我就用正则表达式吧!"现在他们有两个问题。杰米Zawinsky

正则表达式可能有助于验证用户名,但是您不应该尝试将所有这些都打包到一个正则表达式中—那样做是疯狂的。相反,把它分开:

function isValidUsername(username) {
    // may only use the characters a-z, A-Z, 0-9, _, ., and -
    // the characters _, ., and - cannot be the first or last character
    if(!/^[a-zA-Z0-9][a-zA-Z0-9_.-]+[a-zA-Z0-9]$/.test(username)) {
        return false;
    }
    // the characters _, ., and - cannot be next to each other
    // (there must be at least one alphanumeric character between symbols)
    if(/[_.-]{2}/.test(username)) {
        return false;
    }
    // must be between 3 and 15 characters in length,
    // NOT INCLUDING any _, ., and - characters
    // (there must be 3-15 alphanumeric characters)
    var filteredUsername = username.replace(/[^a-zA-Z0-9]/g, '');
    if(filteredUsername.length < 3 || filteredUsername.length > 15) {
        return false;
    }
    return true;
}

我认为结果比将它们全部打包到一个正则表达式中更容易维护,并且您可能不会有任何性能问题。

您可以使用带有优化后的最后部分的纯1-regex解决方案:

^(?=(?:[^a-zA-Z0-9]*[a-zA-Z0-9]){3,15}[^a-zA-Z0-9]*$)(?![._-])(?!.*[._-][._-])[w.-]+[a-zA-Z0-9]$

参见regex demo(注意,n被添加到字符类中用于多行模式下的演示目的)。

如果应用伪冗长的正则表达式编写风格,可以使这个正则表达式更易于维护和可读:

var re = RegExp(
  "^" +                   // Beginning of a string              
  "(?=(?:[^a-z0-9]*[a-z0-9]){3,15}[^a-z0-9]*$)" + // Must contain 3-15 alphanums
  "(?![._-])" +           // Cannot start with ., _ or -
  "(?!.*[._-][._-])" +    // Cannot contain consecutive .-, -_, .., --, etc.
  "[\w.-]+[a-z0-9]" + // Consists of alphanums only and ends with a letter or digit
  "$",                    // End of a string
      "i");               // Make the pattern case-insensitive
                 
var str = 'azzz-zzzzzzz_AZ0.9';
document.write(str + ": " + re.test(str)+"<br/>");
str = '.azzzzzzz-A_Z09';
document.write(str + ": " + re.test(str));

另外,请注意(?=(?:[^a-z0-9]*[a-z0-9]){3,15}[^a-z0-9]*$) forward遵循对比:

正则表达式原则。

如果可以,请使用互斥的连续标记,以创建对比。这减少了回溯和对广义边界的需求,我在这里包括了遍历。

如果你喜欢保留自己的正则表达式,我仍然建议注释它,并使用不区分大小写的i修饰符来缩短它:

var re = RegExp(
  "^" +                           // Beginning of a string              
  "(?=([a-z0-9][-._]?){3,15}$)" + // Must contain 3-15 alphanums (NOTE: only works if [-._] cannot follow one another)
  "[a-z0-9]+" +                   // Cannot start with ., _ or -, starts only with letter or digit
  "(?:[-._][a-z0-9]+)*" +         // Cannot contain consecutive [._-], does not start/end with [-._]
  "$",                            // End of a string
      "i");                       // Make pattern case insensitive

首先,下面的模式应该是工作的

[a-zA-Z0-9](?:(?![_.-]{2})[a-zA-Z0-9_.-])+[a-zA-Z0-9]

From you conditions:

条件:字符_,.和-不能是

的第一个或最后一个字符
REGEX: [a-zA-Z0-9]...[a-zA-Z0-9]

CONDITION:只能使用字符a-z, a-z, 0-9, _, .和-

REGEX: [a-zA-Z0-9_.-]+

条件:字符_,.和-不能相邻

REGEX:(?![_.-]{2})

*在这里使用负向前看检查

但是…

最后一个条件

条件:长度必须在3到15个字符之间,不包括任何_,.,字符(必须有3-15个字母数字字符)

通过只计数字母数字字符来验证模式,我不知道。

我的结论

我不认为最后一个条件可以适合一个纯正则表达式,一旦你使用[...]+来生成随机模式的匹配器,那么你如何使用向前看来验证这些模式,如果你不知道确切的模式。

最新更新