2011-12-20 29 views
2

我构建了一个node.js应用程序,并将一个unix时间戳的六位数base36表示(以秒为单位)存储为Mongodb中一个_id的第一部分。一个典型的_id是这样的:Javascript正则表达式,适用于六位数的base36数字

"_id" : "lwhlzy/czwszasfgr/a4d18976c1/f835caa1c3/184d06b47f" 

数据的几件被连接,包括时间戳随后进行了一系列散列数据的形成既是GUID和“materialized path

后来查询将选择记录基于时间范围,然后是获取该时期内发生的特定路径事件的路径。这些查询将依赖于rooted regular expressions,所以我需要一个正则表达式,可以找到一系列base36数字:

这是我到目前为止的代码(测试通过节点运行,是的,它是硬编码到六位数字。不会被需要的第七位,直到12月23日2038)

var base36 = "abcdefghijklmnopqrstuvwxyz"; 

// determine how many left-most characters from & to have in common 
// this function works nicely, no problems here 
var getOverlap = function (from, to) { 
    regex = ''; 
    count = to.length; 

    for (i in to) { 
     regex += (i>0?'|':'')+'('+to.slice(0,count)+')'; 
     count--; 
    } 

    result = from.match(RegExp(regex,"ig")); 
    return result[0]; 
}; 

var from = "lec0s0"; 
var to = "lwhvqg"; // generated from: parseInt(Date.now()/1000,10).toString(36) 

var overlap = getOverlap(from,to); 

console.log(from); 
console.log(to); 

var regex = overlap; 
var i = overlap.length; 
// start immediately after the left-most common characters and append the rest of the regex 
while (i<6) { 
    regex += "["; 

    if (from[i] < to[i]) { 
     regex += base36.slice(base36.indexOf(from[i]), base36.indexOf(to[i])+1); 
    } else { 
     regex += base36.slice(base36.indexOf(from[i])) + base36.slice(0, base36.indexOf(to[i])+1); 
    } 

    regex += "]"; 
    i++; 
} 

console.log(regex); 
process.exit(); 

将输出是这样的:

l[efghijklmnopqrstuvw][cdefgh][abcdefghijklmnopqrstuv][stuvwxyzabcdefghijklmnopq][abcdefg] 

研究之后,我意识到有两个主要问题与此:1)它的对于真正的范围来说不太合适(它会跳过大量的记录s)和2)Id宁可有字符范围喜欢[e-w]而不是每个字符明确陈述,虽然它仍然有效。

对于输入from="lec0s0"to="lwhvqg"我意识到我错过了这个正则表达式的很大一部分。例如,上面的代码只允许第三个字符的范围从c-h,但该位置需要在第二个字符增加之前达到“z”。我确定我确实需要一个正则表达式,看起来更像是这样的:

l[e-v][0-9a-z][0-9a-z][0-9a-z][0-9a-z]|l[e-w][c-g][0-9a-z][0-9a-z][0-9a-z]|l[e-w][c-h][0-9a-u][0-9a-z][0-9a-z]|l[e-w][c-h][0-9a-v][0-9a-o][0-9a-z]|l[e-w][c-h][0-9a-v][0-9a-q][0-9a-g] 

所以我的问题是:我是对的结束正则表达式需要像后者之上?如果是这样,我该如何修改代码来生成它?

在此先感谢!

回答

1

您当前的模式会匹配来自le0000和,你其实是想匹配:

lec0s[0-9a-z]|lec0[t-z][0-9a-z]{1}|lec[1-9a-z][0-9a-z]{2}|le[d-z][0-9a-z]{3}|l[f-v][0-9a-z]{4}|lw[0-9a-g][0-9a-z]{3}|lwh[0-9a-u][0-9a-z]{2}|lwhv[0-9a-p][0-9a-z]{1}|lwhvq[0-9a-g] 

下面的函数应该给你你需要的正则表达式:

function getRegex(from,to) { 
    var base36 = 'abcdefghijklmnopqrstuvwxyz', 
     getRange = function(f,t) { 
      if(f == t) { 
       return f; 
      } 
      if(base36.indexOf(f) >= base36.indexOf(t)) { 
       return t; 
      } 
      if(t <= '9' || f >= 'a'){ 
       return '[' +f+'-'+t+']'; 
      } 
      return '[' +f+(f<'9'?'-9':'')+(t>'a'?'a-':'')+t+']';  
     }, 
     from = from.split(''), 
     to = to.split(''), 
     prefix='', 
     regex=[], 
     tmp,i,l; 

    for(i=0,l=from.length;i<l;i++) { 
     if(from[i]!=to[i]) { 
      break; 
     } 
     prefix+=from[i]; 
    } 
    from.splice(0,prefix.length); 
    to.splice(0,prefix.length); 

    i = from.length; 
    while(i--) { 
     tmp = prefix+from.slice(0,i).join(''); 
     if(from[i] == 'z') { 
      tmp+='z'; 
     } 
     else if(from.length-i == 1) { 
      tmp += getRange(from[i],'z'); 
     } 
     else if(i) { 
      tmp += getRange(base36.charAt(base36.indexOf(from[i])+1),'z'); 
      tmp += '[0-9a-z]{'+(from.length-i-1)+'}'; 
     } 
     else { 
      tmp += getRange(base36.charAt(base36.indexOf(from[i])+1),base36.charAt(base36.indexOf(to[i])-1)); 
      tmp += '[0-9a-z]{'+(from.length-i-1)+'}'; 
     } 
     regex.push(tmp); 
    } 
    for(i=1,l=to.length;i<l;i++) { 
     tmp = prefix+to.slice(0,i).join(''); 
     if(to[i] == '0') { 
      tmp+='0'; 
     } 
     else if(to.length-i == 1) { 
      tmp += getRange('0',to[i]); 
     } 
     else { 
      tmp += getRange('0',base36.charAt(base36.indexOf(to[i])-1)); 
      tmp += '[0-9a-z]{'+(from.length-i-1)+'}'; 
     } 
     regex.push(tmp); 
    } 

    return regex.join('|'); 
} 

你能活着看到它这里:http://jsfiddle.net/3cu52/3/

+0

看起来不错,谢谢! – talentedmrjones 2011-12-21 19:34:47

+0

嘿,我得到这个错误:“范围乱序在字符类”为这个正则表达式:“lwq0x [8-9a-z] | lwq0 [yz] [0-9a-z] {1} | lwq [1 -9a-Z] [0-9A-Z] {2} | LW [RQ] [0-9A-Z] {3} | LWR [0-9A-U] [0-9A-Z] {2} | lwrv [0-9a-k] [0-9a-z] {1} | lwrvl [0-8]“ 我认为这是”rq“。有任何想法吗?谢谢! – talentedmrjones 2011-12-25 18:36:50

+1

现在已经添加了'getRange'中的缺失检查。看看我更新的答案 - 我也更新了小提琴,寻找行'if(base36.indexOf(f)> = base36.indexOf(t))' – 2011-12-25 21:46:38

1

我只是想在标记位置指出在你的模式

l[e-v][0-9a-z][0-9a-z][0-9a-z][0-9a-z]|l[e-w][c-g][0-9a-z][0-9a-z][0-9a-z]|l[e-w][c-h][0-9a-u][0-9a-z][0-9a-z]|l[e-w][c-h][0-9a-v][0-9a-o][0-9a-z]|l[e-w][c-h][0-9a-v][0-9a-q][0-9a-g] 

l[e-v][0-9a-z][0-9a-z][0-9a-z][0-9a-z]|lw[c-g][0-9a-z][0-9a-z][0-9a-z]|lwh[0-9a-u][0-9a-z][0-9a-z]| ... 
             ^        ^^ 

一个错误,你不需要重复范围,不必要的,因为你所涵盖的模式开始于“乐”在第一个选择。

+0

哦,我明白了!是的,这是非常有意义的,谢谢!任何想法如何编码?我确定我可以得到它,但我的大脑越来越慢,我们越来越接近假期:) – talentedmrjones 2011-12-20 22:05:06

+0

对不起在德国睡觉的时间。通常我会说,正则表达式不擅长检查数字范围,你应该提取数字并使用正常数字比较器。但我不知道基地是否存在这样的事情36。 – stema 2011-12-20 22:15:53

相关问题