2011-12-20 33 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

相關問題