6

テキストから二重の単語を抽出するためのこの正規表現があります

/[A-Za-z]+\s[A-Za-z]+/g

そして、このサンプルテキスト

Mary had a little lamb

私の出力はこれです

[0] - Mary had; [1] - a little;

私の期待する出力はこれですが:

[0] - Mary had; [1] - had a; [2] - a little; [3] - little lamb

どうすればこの出力を達成できますか?私が理解しているように、検索のインデックスは最初の一致の最後に移動します。どうすれば一言戻すことができますか?

4

6 に答える 6

6

String.replace 関数の悪用

関数を使ってちょっとしたトリックを使いreplaceます。関数は一致をループし、replace関数を指定できるため、可能性は無限大です。結果は になりますoutput

var output = [];
var str = "Mary had a little lamb";
str.replace(/[A-Za-z]+(?=(\s[A-Za-z]+))/g, function ($0, $1) {
    output.push($0 + $1);
    return $0; // Actually we don't care. You don't even need to return
});

出力には入力文字列の重複部分が含まれるため、先読み 1を使用して現在の単語を照合するときに、次の単語を消費しないようにする必要があります。

正規表現/[A-Za-z]+(?=(\s[A-Za-z]+))/gは、私が上で述べたこととまったく同じように動作します: 部分 (正規表現の開始) で一度に 1 つの単語のみを消費し、次の単語2[A-Za-z]+を先読みし、一致したテキストもキャプチャします。(?=(\s[A-Za-z]+))

関数に渡されたreplace関数は、最初の引数として一致した文字列を受け取り、後続の引数でキャプチャされたテキストを受け取ります。(他にもあります-ドキュメントを確認してください-ここでは必要ありません)。先読みはゼロ幅(入力は消費されない) であるため、一致全体も最初の単語であることが便利です。先読みのキャプチャ テキストは、2 番目の引数に入ります。

RegExp.exec による適切な解決策

String.replace置換結果はまったく使用されないため、関数には置換オーバーヘッドが発生することに注意してください。これが受け入れられない場合はRegExp.exec、ループ内の関数を使用して上記のコードを書き直すことができます。

var output = [];
var str = "Mary had a little lamb";
var re = /[A-Za-z]+(?=(\s[A-Za-z]+))/g;
var arr;

while ((arr = re.exec(str)) != null) {
    output.push(arr[0] + arr[1]);
}

脚注

  1. 可変幅の否定後読みをサポートする正規表現の他のフレーバーでは、前の単語を取得することは可能ですが、JavaScript 正規表現は否定後読みをサポートしていません!

  2. (?=pattern)先読みの構文です。

付録

String.matchgフラグを使用するとキャプチャ グループが無視されるため、ここでは使用できません。入力の消費を回避し、重複するテキストと一致させるためにルックアラウンドが必要なため、正規表現ではキャプチャ グループが必要です。

于 2012-12-29T14:09:29.667 に答える
4

正規表現なしで実行できます

"Mary had a little lamb".split(" ")
      .map(function(item, idx, arr) { 
          if(idx < arr.length - 1){
              return item + " " + arr[idx + 1];
          }
       }).filter(function(item) {return item;})
于 2012-12-29T13:07:58.397 に答える
2

これは正規表現以外の解決策です(実際には通常の問題ではありません)。

function pairs(str) {
  var parts = str.split(" "), out = [];
  for (var i=0; i < parts.length - 1; i++) 
    out.push([parts[i], parts[i+1]].join(' '));
  return out;
}

文字列を渡すと、配列が返されます。

デモ


補足: 入力に単語以外が含まれていることが心配な場合 (正規表現のケースを作成してください!) 、ループ内parts[i]およびループparts[i+1]内でテストを実行できforます。テストが失敗した場合: それらを にプッシュしないでくださいout

于 2012-12-29T13:20:33.347 に答える
1

あなたが好きな方法はこれかもしれません:

var s = "Mary had a little lamb";

// Break on each word and loop
s.match(/\w+/g).map(function(w) {

    // Get the word, a space and another word
    return s.match(new RegExp(w + '\\s\\w+'));

// At this point, there is one "null" value (the last word), so filter it out
}).filter(Boolean)

// There, we have an array of matches -- we want the matched value, i.e. the first element
.map(Array.prototype.shift.call.bind(Array.prototype.shift));

これをコンソールで実行すると、["Mary had", "had a", "a little", "little lamb"].

このようにして、元の正規表現を保持し、その中で必要な他のことを行うことができます。ただし、実際に機能させるためにいくつかのコードがあります。

ちなみに、このコードはクロスブラウザーではありません。次の機能は、IE8 以下ではサポートされていません。

  • Array.prototype.filter
  • Array.prototype.map
  • 関数.プロトタイプ.バインド

しかし、それらは簡単にシム可能です。または、同じ機能を で簡単に実現できforます。

于 2012-12-29T14:11:24.560 に答える
0

どうぞ:

正規表現の内部ポインターが実際にどのように機能するのかまだわからないので、少し例を挙げて説明します。

Mary had a little lambこの正規表現で/[A-Za-z]+\s[A-Za-z]+/g

ここでは、regex: の最初の部分[A-Za-z]+が一致Maryするため、ポインターは末尾になります。y

Mary had a little lamb
    ^

次の部分 ( \s[A-Za-z]+) では、スペースの後に別の単語が続くので...

Mary had a little lamb
        ^

ポインターは、単語hadが終わる場所になります。これがあなたの問題です。正規表現の内部ポインタを望まずに増やしていますが、これはどのように解決されますか? ルックアラウンドはあなたの友達です。ルックアラウンド (先読みと後読み) を使用すると、正規表現のメインの内部ポインターを増やすことなく、テキストをウォークスルーできます (そのために別のポインターを使用します)。

したがって、最後に、必要なものに一致する正規表現は次のようになります。([A-Za-z]+(?=\s[A-Za-z]+))

説明:

その正規表現について知らないと思うのはその(?=\s[A-Za-z]+)部分だけです。これは、の後に単語が続く必要があることを意味し[A-Za-z]+ます。そうしないと、正規表現は一致しません。そして、これはまさにあなたが望んでいるように見えるものです。なぜなら、内部ポインターは増加せず、最後の単語の後に単語が続かないため、最後の単語以外のすべての単語に一致するからです。

次に、それができたら、今行っていることを置き換えるだけで済みます。

ここに実際の例、DEMOがあります。

于 2012-12-29T13:13:50.363 に答える
0

文字ストリームをトークン化するのは実際には Regex のタスクであり、トークンをどうするかの決定はビジネス ロジックに任されているため、「先読み」の概念を十分に賞賛して、pairwise関数 ( demo ) を提案します。少なくとも、それは私の意見です。

残念なことに、Javascript にはまだペアワイズがありませんが、これで実現できます。

function pairwise(a, f) {
  for (var i = 0; i < a.length - 1; i++) {
     f(a[i], a[i + 1]);
  }
}

var str = "Mary had a little lamb";

pairwise(str.match(/\w+/g), function(a, b) {
  document.write("<br>"+a+" "+b);
});

​
于 2012-12-29T18:57:41.473 に答える