关于一段正则表达式的问题(来自backbone源代码)

aircloud
  • 989

最近在学习backbone的源代码,已经总结的差不多了,但是还有一点没有完全理解,就是backbone路由正则表达式的部分:(写了一点注释 但是不一定对)

  var optionalParam = /\((.*?)\)/g;
  //匹配(?:或者:加一个单词
  var namedParam    = /(\(\?)?:\w+/g;
  //匹配*加上一个单词
  var splatParam    = /\*\w+/g;
  //匹配正则表达式中常用的这些字符
  var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;

  //......略去一些内容
   _routeToRegExp: function(route) {
      route = route.replace(escapeRegExp, '\\$&')//这个匹配的目的是将正则表达式字符进行转义
                   .replace(optionalParam, '(?:$1)?')
                   .replace(namedParam, function(match, optional) {
                     return optional ? match : '([^/?]+)';
                   })
                   .replace(splatParam, '([^?]*?)');
      return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
    },

我不太清楚这个_routeToRegExp函数具体每一步骤执行的意义,包括上文四个先前定义的正则表达式。

也可能是自己之前正则表达式的基础稍微弱些,已经写了注释的也可能理解的不对..

想请经验人士帮忙解释一下..谢谢?

附backbone源代码链接: https://github.com/jashkenas/...

回复
阅读 2.5k
1 个回答
var optionalParam = /\((.*?)\)/g; // 匹配(....)格式的,可选参数
var namedParam    = /(\(\?)?:\w+/g; // 匹配(?:...或者:...的,命名参数
var splatParam    = /\*\w+/g; // 匹配*...
var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g; // 匹配正则表达式中常用的这些字符

...
_routeToRegExp: function(route) {
    // 此函数将路由规则,变成正则表达式,用于后续直接匹配路由地址用
    route = route.replace(escapeRegExp, '\\$&')
        // 将正则表达式字符进行转义,防止生成的正则表达式将这些原本为字符串的字符解释为正则特殊字符
        .replace(optionalParam, '(?:$1)?')
        // 将可选参数部分,变为正则表达式
        // 假设原本匹配的是(xxx)可选参数,变为正则表达式(?:xxx)?,也就是匹配xxx最多1次且不捕获
        .replace(namedParam, function(match, optional) {
            return optional ? match : '([^/?]+)';
        })
        // .replace第二个参数为function时,
        // 第一个参数是整个被匹配到的字符串,后面的参数是匹配到的子分组
        // option为第一个匹配到的子分组,也就是上面namedParam对应的(\(\?)?部分,
        // 实际也就是匹配到(?或者空(对应上面namedParam匹配到(?:...和:...而言)
        // 如果不为空(即?:...),直接返回整个匹配元素,也就是保持(?:...格式不变,
        // 因为这个语法已经是正则写法:匹配一个词,不捕获
        // 如果为空(也就是说原来是匹配到:...),则替换成正则表达式:([^/?]+)
        // 即非/和?的一个以上的字符
        // 也就是到时候实际匹配URL的时候,捕获的是/..../中间的值,或者是/....结尾的一段
        .replace(splatParam, '([^?]*?)');
        // 将通配符匹配*....替换为正则表达式([^?]*?)
        // 次表达式表示匹配非问号的单词0个字或以上,并捕获
    return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
    // 最后这个,拼凑并生成用于直接匹配URL的正则表达式
    // 加上头尾标识符^和$
    // 另外,后面被丢弃的分组(?:\\?([\\s\\S]*))?这里表示的是,匹配地址中....?a=foo&b=bar这类请求参数
},
宣传栏