我需要定义一堆矢量序列,它们是左,下,右,上的一系列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']
我是否可以使用现有的库来生成 所有匹配 ?
修改
我意识到我只需要 或 语句,因为thing or nothing
可以选择a或b指定可选项,两者都可以{ {1}}。我可以使用另一种语言来定义我想要做的事情吗?
答案 0 :(得分:2)
通过将@Dukeling提供的链接的java代码翻译成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
1}}被翻译为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"]
最后一部分是一个小小的hack-ish,因为它依赖于µ
不在字符串中(对我来说不是问题)并且解决了一个错误,其中一个)
在最后输入字符串导致输出错误,方法是在每个字符串的末尾插入µ
,然后从结果中删除它。我很乐意有人建议一个更好的方法来处理这些问题,因此它可以作为一个更通用的解决方案。
这段代码尽我所能。谢谢你的帮助!
答案 1 :(得分:1)
我想你用树做的事情很简单(只要它只是或者语句)。
将a(b|c)d
(或任何or-statement)解析为树,如下所示:a
包含子b
和c
,b
和{{1}有一个共同的孩子c
。 d
和b
都可以包含0个或更多节点(在c
中可以是c
,在这种情况下(部分)树将是g(e|f)h
或者a -> g -> e/f (2 nodes) -> h -> d
可以为空,在这种情况下(部分)树将是c
,但实际的物理空节点可以简化在尝试编写代码时应该看到的内容。 / p>
使用递归或堆栈生成树应该不会太困难。
一旦你有了一棵树,递归迭代整个事物并生成所有字符串是微不足道的。
此外,here是指向类似问题的链接,提供一两个图书馆。
修改强>
a -> d
- 好吧,也许不是
Here是一个有点复杂的例子(Java),可能需要一些关于堆栈的高级知识。
由于在每个"shouldn't be too difficult"
,((
,))
等之间插入一个特殊字符,Here是一个稍微简单的版本(Java)。
请注意,这些都不是特别有效,重点是了解这个想法。
答案 2 :(得分: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"]