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']

すべての一致を生成するために使用できる既存のライブラリはありますか?

編集

オプションのものはおそらく a または b で指定できるため、orステートメントのみが必要になることに気付きました。私がやろうとしていることを定義するために使用できる別の言語はありますか?thing or nothing(a|b|)

4

3 に答える 3

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

2 つ以上の連続したブラケットを処理できるように、1 行だけ変更し、元の翻訳をコメントに残しました。

結果を出力する代わりに、結果の配列を返す関数も追加しました...

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"]

最後の部分は、文字列に含まれていないことに依存してµいるため (私にとっては問題ではありません)、少しハックっぽいですが、入力文字列の末尾に a を挿入することで、誤った出力を引き起こしていた 1 つのバグを解決します)µ各文字列を検索し、結果からそれを取り除きます。誰かがこれらの問題を処理するためのより良い方法を提案してくれるとうれしいです。そうすれば、より一般的な解決策として機能します。

このコードはそのままで、私が必要とするすべてのことを行います。ご助力いただきありがとうございます!

于 2013-02-11T10:58:05.677 に答える
1

これは、(a | b)と(a | b |)の可能性の解析に対処し、可能なサブストリングの配列を作成し、この回答に基づいて一致を構成するJavaScriptの例です。

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"]
于 2013-02-10T19:34:12.320 に答える
1

私はあなたが試みていることは木で非常に簡単だと思います(それがor-ステートメントだけである限り)。

a(b|c)d次のように(または任意のorステートメント)をツリーに解析します。abcbc持ち、相互に子を持ちdます。b両方ともc0個以上のノードで構成cできますg(e|f)h(この場合、ツリー(の一部)は空になるa -> g -> e/f (2 nodes) -> h -> dc、空になる可能性があります。この場合、ツリー(の一部)は空にa -> dなりますが、実際の物理的な空のノードは単純化されます。コードを書き込もうとしたときに表示されるもの)。

ツリーの生成は、再帰またはスタックのいずれかでそれほど難しくないはずです。

ツリーができたら、すべてを再帰的に繰り返してすべての文字列を生成するのは簡単です。

また、ここに同様の質問へのリンクがあり、ライブラリを1つか2つ提供しています。

編集:

"shouldn't be too difficult"-大丈夫、多分そうではない

これはやや複雑な例(Java)であり、スタックに関する高度な知識が必要になる場合があります

、、、などの間((に特殊文字を挿入したおかげで、これは少し単純なバージョン(Java)です。))|(

これらはどちらも特に効率的ではないことに注意してください。重要なのは、アイデアを伝えることだけです。

于 2013-02-10T14:19:37.450 に答える