2013-02-10 66 views
1

的子集,我需要定義一堆載體序列,這些都是一系列的LDRU爲左,下,右,上,x爲休息的所有比賽。有可選的部分,和/或部分。我一直在使用我自己發明的系統來記錄它,但我想爲其他可能非程序員閱讀的文檔記錄這一點。生成的正則表達式

我現在想用正則表達式的一個子集(我不打算使用任何通配符,或例如無限重複)來定義矢量序列和腳本生成的所有可能的匹配字符串...

/LDR/ produces ['LDR'] 
/LDU?R/ produces ['LDR','LDUR'] 
/R(LD|DR)U/ produces ['RLDU','RDRU'] 
/DxR[DL]U?RDRU?/ produces ['DxRDRDR','DxRDRDRU','DxRDURDR','DxRDURDRU','DxRLRDR','DxRLRDRU','DxRLURDR','DxRLURDRU'] 

有一個現有的圖書館中,我可以用它來生成所有匹配

編輯

我意識到我將只需要聲明,可選的東西可以通過也許,或b來指定,既可選可能是(a|b|)。是否有另一種語言可以用來定義我想要做的事情?

+0

你可以爲你自己的正則表達式編寫一個解析器,然後遍歷所有的可能性。但是,杜克林給出的鏈接有一個現有的圖書館來完成這一代。 – nhahtdh 2013-02-10 14:04:23

+0

@Dukeling:他有正則表達式,他想要生成所有匹配它的字符串。 – nhahtdh 2013-02-10 14:04:52

+0

@billy ...只是讓你知道,我在下面更新了我的答案 - 我的本地解析器爲「?」現在似乎產生了比賽...有趣的挑戰。 – 2013-02-11 06:50:44

回答

2

通過翻譯的Java代碼形成以@Dukeling到JavaScript提供的鏈接,我想我已經解決了我的問題......

var Node = function(str){ 
    this.bracket = false; 
    this.children = []; 
    this.s = str; 
    this.next = null; 
    this.addChild = function(child){ 
     this.children.push(child); 
    } 
} 

var printTree = function(root,prefix){ 
    prefix = prefix.replace(/\./g, ""); 
    for(i in root.children){ 
    var child = root.children[i] 
    printTree(child, prefix + root.s); 
    } 
    if(root.children.length < 1){ 
    console.log(prefix + root.s); 
    } 
} 

var Stack = function(){ 
    this.arr = [] 
    this.push = function(item){ 
     this.arr.push(item) 
    } 
    this.pop = function(){ 
     return this.arr.pop() 
    } 
    this.peek = function(){ 
     return this.arr[this.arr.length-1] 
    } 
} 

var createTree = function(s){ 

    // this line was causing errors for `a(((b|c)d)e)f` because the `(((` was only 
    // replacing the forst two brackets. 
    // var s = s.replace(/(\(|\||\))(\(|\||\))/g, "$1.$2"); 
    // this line fixes it 
    var s = s.replace(/[(|)]+/g, function(x){ return x.split('').join('.') }); 

    var str = s.split(''); 
    var stack = new Stack(); 
    var root = new Node(""); 
    stack.push(root); // start node 
    var justFinishedBrackets = false; 
    for(i in str){ 
     var c = str[i] 
     if(c == '('){ 
      stack.peek().next = new Node("Y"); // node after brackets 
      stack.peek().bracket = true; // node before brackets 
     } else if (c == '|' || c == ')'){ 
      var last = stack.peek(); // for (ab|cd)e, remember b/d so we can add child e to it 
      while (!stack.peek().bracket){ // while not node before brackets 
       stack.pop(); 
      } 
      last.addChild(stack.peek().next); // for (b|c)d, add d as child to b/c 
     } else { 
      if (justFinishedBrackets){ 
       var next = stack.pop().next; 
       next.s = "" + c; 
       stack.push(next); 
      } else { 
       var n = new Node(""+c); 
       stack.peek().addChild(n); 
       stack.push(n); 
      } 
     } 
     justFinishedBrackets = (c == ')'); 
    } 
    return root; 
} 

// Test it out 
var str = "a(c|mo(r|l))e"; 
var root = createTree(str); 
printTree(root, ""); 
// Prints: ace/amore/amole 

我只是改變了一條線,允許兩個以上連續的支架進行處理,並留在評論

我還添加了一個函數返回,而不是將它們打印結果的陣列,原文翻譯...

var getTree = function(root,prefix){ 
    this.out = this.out || [] 
    prefix = prefix.replace(/\./g, ""); 
    for(i in root.children){ 
    var child = root.children[i] 
    getTree(child, prefix + root.s, out); 
    } 
    if(root.children.length < 1){ 
    this.out.push(prefix + root.s); 
    } 
    if(!prefix && !root.s){ 
    var out = this.out; 
    this.out = null 
    return out; 
    } 
} 

// Test it 
var str = "a(b|c)d"; 
var root = createTree(str); 
console.log(getTree(root, "")); 
// logs ["abd","acd"] 

最後一部分,允許空字符串了,所以... (ab|c|)意味着abcnothing,以及方便快捷,使ab?c被翻譯成a(b|)c

var getMatches = function(str){ 
    str = str.replace(/(.)\?/g,"($1|)") 
    // replace all instances of `(???|)` with `(???|µ)` 
    // the µ will be stripped out later 
    str = str.replace(/\|\)/g,"|µ)") 
    // fix issues where last character is `)` by inserting token `µ` 
    // which will be stripped out later 
    str = str+"µ" 
    var root = createTree(str); 
    var res = getTree(root, ""); 
    // strip out token µ 
    for(i in res){ 
     res[i] = res[i].replace(/µ/g,"") 
    } 
    // return the array of results 
    return res 
} 

getMatches("a(bc|de?)?f"); 
// Returns: ["abcf","adef","adf","af"] 

最後一部分是有點劈十歲上下,因爲它依賴於µ字符串(不是我的問題),在沒有被解決了一個錯誤,其中)在輸入字符串的結束是導致不正確的輸出,在每個字符串的末尾插入一個µ,然後從結果中剝離它。我會很高興有人提出更好的方法來處理這些問題,因此它可以作爲更一般的解決方案。

這個代碼,因爲它代表了我所需要的一切。感謝你的幫助!

+0

我再次使用這段代碼做了其他的事情,我開始看到這個實現的一些限制。我仍然不喜歡使用'μ'令牌。應該可以構建數組,並使用字符串作爲令牌的值和數字。另外,Google搜索後,發現一些有用的,相關的東西。 http://regldg.com/docs/index.php,https://github.com/bluezio/xeger,http://stackoverflow.com/questions/20080789/given-a-regular-expression-how-would-我生成所有字符串,即匹配它,http://stackoverflow.com/questions/15950113/generate-all-valid-values-for-a-regular-expression – 2014-02-21 01:54:03

1

我想象你正在嘗試使用樹很容易(只要它只是或者語句)。

解析a(b|c)d(或任何或語句)成樹如下:a有孩子bcbc有一個共同的孩子dbc都可以由0個或更多個節點組成(如c可以是g(e|f)h,在這種情況下(樹的一部分)將是a -> g -> e/f (2 nodes) -> h -> dc可以是空的,在這種情況下(樹的一部分)將是a -> d,但一個實際的物理空節點可能會簡化一些事情,您在嘗試編寫代碼時應該會看到這些內容)。

無論是遞歸還是堆棧,樹的生成不應該太困難。

一旦你有一棵樹,遞歸遍歷整個事物並生成所有字符串是微不足道的。

另外,here是一個類似問題的鏈接,提供一個或兩個庫。

編輯:

"shouldn't be too difficult" - 好吧,也許不是

Here是一個比較複雜的例子(JAVA),可能需要大約堆了一些先進的知識。

Here是一個稍微簡單的版本(JAVA)由於將每個(())|(之間的特殊字符等

注意,這些都不是特別有效的,關鍵是剛拿到的想法跨越。

+0

我希望JavaScript如果可能的話,我很方便與JavaScript,但我不知道如何寫一個解析器(我很想學習雖然)。這種方法似乎是我正在尋找的答案 - 你有沒有任何指針,我會如何去做你的步驟一和二(創建解析樹,遍歷樹)。例如,我有點困惑,如何創建一個有相互的孩子的樹,以及如何與相互的孩子一起遍歷一棵樹。 – 2013-02-10 14:38:33

+0

這看起來不錯 - 我相信我能翻譯這個沒有問題, - 似乎正是我所需要的。謝謝,我會讓你知道我如何繼續。 – 2013-02-10 21:18:56

+0

我翻譯了它,添加了幾個方法,它的效果都很好 - 謝謝! http://stackoverflow.com/a/14810830/665261 – 2013-02-11 12:39:20

1

這是一個JavaScript示例,它解析了分析(a | b)和(a | b |)的可能性,創建了一個可能的子串數組,並根據this answer組成匹配。

var regex = /\([RLUD]*\|[RLUD]*\|?\)/, 
    str = "R(LD|DR)U(R|L|)", 
    substrings = [], matches = [], str_tmp = str, find 

while (find = regex.exec(str_tmp)){ 
    var index = find.index 

    finds = find[0].split(/\|/) 
    substrings.push(str_tmp.substr(0, index)) 

    if (find[0].match(/\|/g).length == 1) 
    substrings.push([finds[0].substr(1), finds[1].replace(/.$/, '')]) 
    else if (find[0].match(/\|/g).length == 2){ 
    substrings.push([finds[0].substr(1), ""]) 
    substrings.push([finds[1], ""]) 
    } 

    str_tmp = str_tmp.substr(index + find[0].length) 
} 
if (str_tmp) substrings.push([str_tmp]) 
console.log(substrings) //>>["R", ["LD", "DR"], "U", ["R", ""], ["L", ""]] 

//compose matches 
function printBin(tree, soFar, iterations) { 
    if (iterations == tree.length) matches.push(soFar) 
    else if (tree[iterations].length == 2){ 
     printBin(tree, soFar + tree[iterations][0], iterations + 1) 
     printBin(tree, soFar + tree[iterations][1], iterations + 1) 
    } 
    else printBin(tree, soFar + tree[iterations], iterations + 1) 
} 
printBin(substrings, "", 0) 
console.log(matches) //>>["RLDURL", "RLDUR", "RLDUL", "RLDU", "RDRURL", "RDRUR", "RDRUL", "RDRU"] 
+0

這很有趣。當您向輸入字符串添加第三個問號時似乎有一個錯誤。同樣,在我的情況下,我需要一種方法來表示'this'或'that',以代替LDD?R'我可以編寫'LD(D |)R'並使用相同的語法來編寫'L(DL | RD)U'(擴展爲'LDLU'和'LRDU')。謝謝你的幫助。我將發佈我最終在這裏使用的代碼。 – 2013-02-11 09:17:09

+0

我加了一個答案,你可能會感興趣... http://stackoverflow.com/a/14810830/665261 – 2013-02-11 12:38:51

+0

@比利......看起來有趣,我會從中學習。我發現了一個小錯誤,但是我的索引樹實際上並不是兩個以上的「?」。不過,這是一個創造性的努力,也許我會努力讓它工作。 – 2013-02-11 16:22:46