8

たとえば、文字の銀行のようなものを識別し、それを正規表現内で使用できる正規表現を実行できるようにしたいと思い[dgos]ます...しかし、その文字が使用されるたびに、銀行からそれが奪われます。

では、どういうわけかその\1文字列 ( dgos) を表すことができるとしましょう。次のような正規表現を書くことができます。

^\1{1}o\1{2}$

そしてそれは基本的に一致します:
\1{1}= [dgos]{1}
o
\1{2}=[dgos]{2}最初のもので使用されたものは何でもマイナス

一致には 、 、 などを含めることができますがgooddosg(sogdsods2s回使用する必要があるため) またはsooo(を 2 回使用する必要があるため) は含めませんo

また、複数回使用できる文字を識別できるようにしたいと考えています。私はこれを自分で書き始めましたが、どこから始めればよいかさえわからないことに気付きました。最小限の入力で正規表現を簡単に生成できるほど十分です。

条件と複数の正規表現の組み合わせを使用した以下のソリューションがあります(その答えについての考えを自由にコメントしてください-おそらくそれが私がしなければならない方法ですか?)が、可能であれば単一の正規表現ソリューションを好む...可能であれば、よりエレガントで効率的なもの。

より高いレベルのエレガンスと単一の正規表現部分は単なる私の好みであることに注意してください。最も重要なことは、それが機能し、パフォーマンスが十分に優れていることです。

4

5 に答える 5

1

@TomLordの回答に基づいて、必ずしも文字列を使い果たす必要がないことを考慮して、肯定的なものではなく否定的な先読みアサーションを使用できます。あなたの例D<2 from bank>R<0-5 from bank>では、その正規表現は次のようになります

/^(?![^o]*o[^o]*o)(?![^a]*a[^a]*a)(?![^e]*e[^e]*e[^e]*e)(?![^s]*s[^s]*s)d[oaes]{2}r[oaes]{0,5}$/i

説明:

^                        # Start of string
(?![^o]*o[^o]*o)         # Assert no more than one o
(?![^a]*a[^a]*a)         # Assert no more than one a
(?![^e]*e[^e]*e[^e]*e)   # Assert no more than two e
(?![^s]*s[^s]*s)         # Assert no more than one s
d                        # Match d
[oaes]{2}                # Match two of the letters in the bank
r                        # Match r
[oaes]{0,5}              # Match 0-5 of the letters in the bank
$                        # End of string

(?!.*o.*o)の代わりに書くこともできます(?![^o]*o[^o]*o)が、後者の方が高速ですが、読みにくいだけです。これを別の方法で書くと、(?!(?:[^o]*o){2})(繰り返し回数が増える場合に便利です)。

そしてもちろん、文字列の「固定」部分の文字数を考慮する必要があります (この場合 (dおよびr) は銀行に干渉しませんが、他の例では干渉する可能性があります)。

于 2013-07-23T13:19:33.627 に答える
0

正規表現でこれを完全に行う方法は考えられませんでしたが、これを思いつくことができました: http://jsfiddle.net/T2TMd/2/

jsfiddle は投稿サイズに制限されているため、そこで大きな辞書を作成できませんでした。180,000 語の辞書を使用したより良い例については、こちらを確認してください。

主な機能:

/*
* filter = regex to filter/split potential matches
* bank = available letters
* groups = capture groups that use the bank
* dict = list of words to search through
*/
var matchFind = function(filter, bank, groups, dict) {
    var matches = [];
    for(var i=0; i < dict.length; i++) {
        if(dict[i].match(filter)){
            var fail = false;
            var b = bank;
            var arr = dict[i].split(filter);
            //loop groups that use letter bank
            for(var k=0; k<groups.length && !fail; k++) {
                var grp = arr[groups[k]] || [];
                //loop characters of that group
                for(var j=0; j<grp.length && !fail; j++) {
                    var regex = new RegExp(b);
                    var currChar = grp.charAt(j);
                    if(currChar.match(regex)) {
                        //match found, remove from bank
                        b = b.replace(currChar,"");
                    } else { 
                        fail = true;
                    }
                }
            }
            if(!fail) {
                matches.push(dict[i]);
            }
        }
    }
    return matches;
}

使用法:

$("#go").click( function() {
    var f = new RegExp($("#filter").val());
    var b = "["+$("#bank").val().replace(/[^A-Za-z]+/g,"").toUpperCase()+"]";
    var g = $("#groups").val().replace(/[^0-9,]+/g,"").split(",") || [];
    $("#result").text(matchFind(f,b,g,dict).toString());
});

シナリオを作成しやすくするために、これも作成しました。

$("#build").click( function() {
    var bank = "["+$("#buildBank").val().replace(/[^A-Za-z]+/g,"").toUpperCase()+"]";
    var buildArr = $("#builder").val().split(",");
    var groups = [];
    var build = "^";
    for(var i=0; i<buildArr.length; i++) {
        var part = buildArr[i];
        if(/\</.test(part)) {
            part = "(" + bank + part.replace("<", "{").replace(">", "}").replace("-",",") + ")";
            build = build + part;
            groups.push(i+1);
        } else {
            build = build + "("+part+")";
        }
    }
    build = build + "$";
    $("#filter").val(build);
    $("#bank").val(bank);
    $("#groups").val(groups.toString());
    $("#go").click();
});

これは Scrabble で役に立ちます。単語が "D" で始まらなければならない位置にいて、その "D" と並列単語の "R" の間に 2 つのスペースがあるとしますOAEES。あなたのレターバンク。Dで始まる必要があるため、ビルダーに入れるD,<2>,R,<0-3>ことができます。次に、銀行からの2文字が必要であり、次にRがあり、最大3文字を使用する必要があります(間に2を使用しているため) D および R)。

ビルダーはレター バンクを使用し、可能な一致をフィルター処理するために使用されるものに変換D,<2>,R,<0-3>します。^(D)([OAEES]{2})(R)([OAEES]{0,5})$次に、それらの可能な一致を使用して、レターバンクを使用するキャプチャグループを文字ごとに調べ、見つかったときにその正規表現から文字を削除して、そこよりも多くのレターバンク文字が使用されている場合は一致しないようにします。レターバンクにあります。

ここで上記のシナリオをテストします。

于 2013-07-22T15:44:26.803 に答える