当前位置:嗨网首页>书籍在线阅读

21-向前查找

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

17.19 向前查找

如果说熟悉懒惰匹配和贪婪匹配是专业开发者和业余爱好者的分界线,那么使用向前查找则是大师级开发者和专业开发者的分水岭,与锚点和单词边界元字符一样,它也不消费输入。然而,不同于锚点和单词边界的是,它们是通用的:可以匹配任何子表达式却不消费它。事实上,正如单词边界元字符,向前查找的这种不消费的特性,解决了有时候不得不进行“原封不动”的替换的问题。虽然“原封不动”的替换可能是个不错的技巧,但并不是必须掌握的。只要有内容重复,向前查找就是必须的,而且它们可以简化某些特定类型的匹配。

验证密码是否符合预设的规则是一个经典的例子。简单起见,假设密码必须由字母和数字组成,且至少包含一个大写字母、一个数字和一个小写字母。当然,可以使用多个正则表达式来实现它:

function validPassword(p) {
    return /[A-Z]/.test(p) &&          // at least one uppercase letter
        /[0-9]/.test(p) &&             // at least one number
        /[a-z]/.test(p) &&             // at least one lowercase letters
        !/[^a-zA-Z0-9]/.test(p);       // only letters and numbers
} 

假如想将它们组合成一个正则表达式。第一次尝试将以失败告终:

function validPassword(p) {
    return /[A-Z].*[0-9][a-z]/.test(p);
} 

这个表达式对顺序有要求,它不仅要求大写字母出现在数字之前,数字出现在两个小写字母前,而且没有对非法字符做任何校验。实际上也没有一个好办法可以实现它,因为字符在正则表达式运行时就被消费了。

向前查找通过不消费输入来解决这个问题。本质上每个向前查找都是一个不消费输入的独立正则表达式。在JavaScript中,向前查找是这样的((?=)。还有一个“否定向前查找“:((?!))只会匹配不存在于子表达式中的内容。下面可以单独写一个正则表达式来验证密码:

function validPassword(p) {
    return /(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z])(?!.*[^a-zA-Z0-9])/.test(p);
} 

看到这些类似乱码的内容,你可能觉得还不如使用多个正则表达式,至少可读性会更高一些。就这个例子而言,作者同意这种看法。这个例子展示了向前检查(以及否定向前检查)的一个非常重要的使用场景。虽然向前检查确实归属于“高级正则表达式”的范畴,但它对于解决某些特定的问题也很重要。