1

次のコードでは:

"a sasas b".match(/sas/g) //returns ["sas"]

文字列には、実際には2つのsas文字列a [sas]as bとが含まれますa sa[sas] b

両方に一致するように正規表現を変更するにはどうすればよいですか?

もう一つの例:

"aaaa".match(/aa/g); //actually include [aa]aa,a[aa]a,aa[aa]

上記の例だけでなく、一般的に問題を考慮してください。

純粋なRexExソリューションが推奨されます。

4

4 に答える 4

2

このような「マージされた」オカレンスを少なくとも1つ一致させたい場合は、次のようにすることができます。

"a sasas b".match(/s(as)+/g)

一致を個別の結果として取得する場合は、もう少し作業が必要です。これは、正規表現が処理するように設計されている場合ではありません。基本的なアルゴリズムは次のとおりです。

  • 一致を試みます。失敗した場合は、停止します。
  • 興味のある一致を抽出し、それを使ってやりたいことを何でもします。
  • 一致する最初の文字に続く1文字から始めて、元のターゲット文字列のサブ文字列を取得します。
  • このサブストリングを新しい入力として使用して、最初からやり直します。

(より効率的にするには、部分文字列を使用する代わりにオフセットと一致させることができます。その手法については、この質問で説明します。)

たとえば、。で始めます"a sasas b"。最初の試合の後、あなたは"sas"。試合が始まってから1文字始まる部分文字列をとると、"asas b"。次の一致は"sas"ここを見つけます、そしてあなたは再びプロセスを繰り返します"as b"。これは一致しないので、完了します。

于 2012-11-09T03:58:03.830 に答える
1

この大幅に改善された回答は、@EliGassertによるものです。

String.prototype.match_overlap = function(re)
    {
        if (!re.global)
            re = new RegExp(re.source,
                            'g' + (re.ignoreCase ? 'i' : '')
                                + (re.multiline  ? 'm' : ''));
        var matches = [];
        var result;
        while (result = re.exec(this))
            matches.push(result),
            re.lastIndex = result.index + 1;
        return matches.length ? matches : null;
    }

@EliGassertは、文字列全体を文字ごとにウォークスルーする必要はないことを指摘しています。代わりに、どこでも一致を見つけることができ(つまり、アンカーなしで行う)、見つかった一致のインデックスの後に1文字続けます。上記のインデックスを取得する方法を調査しているときに、検索を続行する場所を追跡するためre.lastIndexに使用されるプロパティが実際に設定可能であることがわかりました。これは、私たちがやろうとしていることとかなりうまく機能します。exec

さらに説明が必要なのは始まりだけかもしれません。gフラグがない場合、はexec決して戻らないnull可能性があり(存在する場合は常に1つの一致を返す)、したがって無限ループに入る可能性があります。ただし、match_overlap 設計上、複数の一致を求めるため、非グローバルを グローバルRegExpとして安全に再コンパイルし、設定されている場合はオプションとオプションもインポートできます。 RegExpim

新しいjsFiddleは次のとおりです:http://jsfiddle.net/acheong87/h5MR5/

document.write("<pre>");
document.write('sasas'.match_overlap(/sas/));
document.write("\n");
document.write('aaaa'.match_overlap(/aa/));
document.write("\n");
document.write('my1name2is3pilchard'.match_overlap(/[a-z]{2}[0-9][a-z]{2}/));
document.write("</pre>");​

出力:

sas,sas
aa,aa,aa
my1na,me2is,is3pi
于 2012-11-09T21:21:39.703 に答える
0

これを行う一般的な方法は次のとおりです。

​String.prototype.match_overlap = function(regexp)
    {
        regexp = regexp.toString().replace(/^\/|\/$/g, '');
        var re = new RegExp('^' + regexp);
        var matches = [];
        var result;
        for (var i = 0; i < this.length; i++)
            if (result = re.exec(this.substr(i)))
                matches.push(result);
        return matches.length ? matches : null;
    }

使用法:

var results = 'sasas'.match_overlap(/sas/);

戻り値:

  • array(重複する)一致、またはnull

例:

これがjsFiddleです。

document.write("<pre>");​
document.write('sasas'.match_overlap(/sas/));
document.write("\n");
document.write('aaaa'.match_overlap(/aa/));
document.write("\n");
document.write('my1name2is3pilchard'.match_overlap(/[a-z]{2}[0-9][a-z]{2}/));
document.write("</pre>");​

これを返します:

sas,sas
aa,aa,aa
my1na,me2is,is3pi

説明:

少し説明すると、ユーザーが通常のように、この新しい関数にRegExp オブジェクトを渡すことを目的としています。これから、最初に固定された新しいオブジェクトを作成します(重複する一致を防ぐために、この部分は、自分で問題が発生しない限り、おそらく意味がありません。心配しないでください)。次に、サブジェクト文字列の各サブ文字列と照合し、結果を配列にプッシュします。配列は、空でない場合は返されます(それ以外の場合は戻ります)。ユーザーがすでにアンカーされている式を渡した場合、これは本質的に間違っていることに注意してくださいmatch_overlapmatchRegExpthisnull—最初はアンカーを取り除きましたが、ユーザーの代わりに仮定を立てていることに気付きました。これは避けるべきです。//g最後に、さらに進んで、結果の一致の配列を、オプションで通常発生するものに似た単一の一致結果にマージすることができます。さらに進んで新しいフラグを作成することできます。たとえば //o、オーバーラップマッチングを行うために解析されますが、これは少しおかしくなりつつあります。

于 2012-11-09T04:45:20.247 に答える
0
var match = "a sasas b".match(/s(?=as)/g);

for(var i =0; i != match.length; ++i)
    alert(match[i]);

Q. Sheetsによるコメントとcdhowieによる応答から離れて、私は上記の解決策を思いつきました。それは正規表現で1文字を消費し、残りの一致文字列を先読みします。これらの2つの部分を使用して、正規表現のすべての位置と一致する文字列を作成できます。

一致する(先読み)文字列の残りを実際に結果に含めるために使用できる「検査するが消費しない」演算子があればいいのですが、残念ながら、少なくともJSにはありません。

于 2012-11-09T04:16:37.287 に答える