2013-02-10 1 views
1

мне нужно определить кучу векторных последовательностей, которые все серии L, D, R, U для влево, вниз, вправо, вверх или 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'] 

Есть ли существующая библиотека, которую я могу использовать для генерации все совпадения?

EDIT

я понял, что будет нуждаться только или заявления, так как необязательные вещи могут быть определены , может быть, или б, и по желанию может быть (a|b|). Есть ли другой язык, который я мог бы использовать, чтобы определить, что я пытаюсь сделать?

+0

Вы можете написать парсер для своего собственного регулярного выражения, а затем пройти через все возможности. Но ссылка Dukeling дала имеющуюся библиотеку, чтобы сделать поколение. – nhahtdh

+0

@Dukeling: У него есть регулярное выражение, и он хочет сгенерировать все строки, которые соответствуют ему. – nhahtdh

+0

@billy ... просто чтобы вы знали, я обновил свой ответ ниже - мой доморощенный парсер для «?» теперь, похоже, создает матчи ... Интересный вызов. –

ответ

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|) означает ab или c или nothing, и удобство клавиш, так что 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- i-generate-all-strings-that-match-it, http://stackoverflow.com/questions/15950113/generate-all-valid-values-for-a-regular-expression –

1

Я представляю, что вы пытаетесь довольно легко с деревом (пока это только или-заявления).

Анализировать a(b|c)d (или любой или-заявление) в дерево следующим образом: a имеет детей b и c, b и c имеют взаимное ребенка d. b и c могут состоять из 0 или более узлов (как в c может быть g(e|f)h, в этом случае (часть) дерево будет a -> g -> e/f (2 nodes) -> h -> d или c может быть пустым, и в этом случае (часть) дерево будет a -> d, но фактический физический пустой узел может упростить вещи, которые вы должны увидеть при попытке написать код).

Поколение дерева не должно быть слишком сложным с рекурсией или стеком.

Как только у вас есть дерево, тривиально рекурсивно перебирать всю вещь и генерировать все строки.

Также, here является ссылкой на аналогичный вопрос, предоставляя библиотеку или два.

EDIT:

"shouldn't be too difficult" - хорошо, может быть, не

Here является довольно сложным примером (Java), что может потребоваться некоторые дополнительные знания о стеков.

Here является немного упрощенной версией (Java) благодаря вставке специального символа между каждым ((, )), |( и т.д.

Обратите внимание, что ни один из них особенно эффективны, дела в том только, чтобы получить представление в поперечнике.

+0

Я бы предпочел использовать javascript, если это возможно, мне очень удобно с javascript, но я не знаю, как написать парсер (я бы хотел узнать, хотя). Этот подход, похоже, является ответом, который я ищу, - есть ли у вас какие-либо указатели, как я буду делать шаги один и два (создать дерево синтаксического анализа, пересечь дерево). Я немного запутался, например, как создать дерево с взаимными дочерними элементами, а затем как пересекать дерево вместе с детьми. –

+0

Это выглядит великолепно - я уверен, что смогу перевести это без проблем, - кажется, именно то, что мне нужно. Спасибо, я дам вам знать, как я нахожусь. –

+0

Я перевел его, добавил несколько методов, и все работает отлично - спасибо! http://stackoverflow.com/a/14810830/665261 –

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'). Спасибо за вашу помощь. Я отправлю код, который я, наконец, использую здесь. –

+0

Я добавил ответ, вам может быть интересно ... http://stackoverflow.com/a/14810830/665261 –

+0

@ billy ... выглядит интересно, я узнаю из него. Я обнаружил, что небольшая ошибка, но мое индексное дерево действительно не работает более чем на два «?». Это было творческое усилие, хотя, может быть, я попытаюсь заставить его работать. –

Смежные вопросы