33

私が走るとき

/(a)/g.exec('a a a ').length

私は得る

2

でも戻るべきだと思った

3

a文字列には2ではなく3が含まれているためです。

何故ですか?

RegExで文字列のすべての出現箇所を検索し、それらを反復処理できるようにしたいと思います。

FWIW:node.jsを使用しています

4

9 に答える 9

42

exec()は、最初の一致のキャプチャのセットのみを返し、期待どおりの一致のセットは返しません。つまり、実際に表示されている$0のは、(一致全体、「a」)と$1(最初のキャプチャ)、つまり長さ2の配列です。 一方、次の一致のキャプチャを取得するために再度exec()呼び出すことができるように設計されています。 。MDNから:

正規表現で「g」フラグを使用している場合は、execメソッドを複数回使用して、同じ文字列内の連続する一致を見つけることができます。これを行うと、検索は正規表現のlastIndexプロパティで指定されたstrのサブストリングから開始されます(テストはlastIndexプロパティも進めます)。

于 2012-06-30T00:04:44.423 に答える
34

代わりに使用できますmatch

'a a a'.match(/(a)/g).length  // outputs: 3
于 2012-06-30T00:03:08.843 に答える
18

whileループはあなたを助けることができます

x = 'a a a a';
y = new RegExp(/a/g);
while(null != (z=y.exec(x))) {
   console.log(z);     // output: object
   console.log(z[0]);  // ouput: "a"
}

カウンターを追加すると、その長さがわかります。

x = 'a a a a';
counter = 0;
y = new RegExp(/a/g);
while(null != (z=y.exec(x))) {
   console.log(z);     // output: object
   console.log(z[0]);  // output: "a"
   counter++;
}
console.log(counter);  // output: 4

これは非常に安全です。一致するものが見つからない場合でも、終了するだけでカウンターは0になります。

主な目的は、RegExpを使用して、同じ一致したRegExpの文字列からすべての値をループして取得する方法を説明することです。

于 2018-05-14T13:51:02.213 に答える
8

最初のaのみを一致させます。長さが2である理由は、最初の一致と最初の一致の括弧で囲まれたグループ部分を検索しているためです。あなたの場合、それらは同じです。

この例を考えてみましょう。

var a = /b(a)/g.exec('ba ba ba ');
alert(a);

を出力しますba, a。配列の長さはまだ2ですが、何が起こっているのかがより明確になります。「ba」は完全一致です。 a括弧で囲まれた最初のグループ化の一致です。

MDNドキュメントはこれをサポートしています-最初の一致と含まれているグループのみが返されます。すべての一致を見つけるには、mVChrで指定されているようにmatch()を使用します。

于 2012-06-30T00:07:52.810 に答える
4

コード:

alert('a a a'.match(/(a)/g).length);

出力:

3
于 2012-06-30T00:11:10.990 に答える
2

regexp.exec(str)re = /(a)/g;他の回答で言及されているように、最初の一致または一致全体と最初のキャプチャ(の場合)を返します

const str = 'a a a a a a a a a a a a a';
const re = /a/g;

const result = re.exec(str);
console.log(result);

しかし、それはまた、財産におけるそれの後の位置を覚えregexp.lastIndexています。

次の呼び出しは検索を開始しregexp.lastIndex、次の一致を返します。

一致するものがこれ以上ない場合regexp.execはnullを返しregexp.lastIndex、0に設定されます。

const str = 'a a a';
const re = /a/g;

const a = re.exec(str);
console.log('match : ', a, ' found at : ', re.lastIndex);

const b = re.exec(str);
console.log('match : ', b, ' found at : ', re.lastIndex);

const c = re.exec(str);
console.log('match : ', c, ' found at : ', re.lastIndex);

const d = re.exec(str);
console.log('match : ', d, ' found at : ', re.lastIndex);

const e = re.exec(str);
console.log('match : ', e, ' found at : ', re.lastIndex);

そのため、試合が終了すると停止するwhileループを使用できます。null

const str = 'a a a';
const re = /a/g;

while(match = re.exec(str)){
  console.log(match, ' found at : ', match.index); 
}

于 2019-03-09T00:09:02.830 に答える
1

すでにいくつかの答えがありますが、不必要に複雑です。結果のIDチェックは、常に配列またはのいずれかであるため、過剰ですnull

let text = `How much wood would a woodchuck chuck if a woodchuck could chuck wood?`;
let re = /wood/g;
let lastMatch;

while (lastMatch = re.exec(text)) {
  console.log(lastMatch);
  console.log(re.lastIndex);

  // Avoid infinite loop
  if(!re.global) break;
}

無限ループガードを条件式に移動できます。

while (re.global && (lastMatch = re.exec(text))) {
 console.log(lastMatch);
 console.log(re.lastIndex);
}
于 2021-08-15T14:19:50.967 に答える
0

あなたの例で.match()は、が最良の選択肢です。ただし、サブグループが必要な場合は、ジェネレーター関数を作成できます。

function* execAll(str, regex) {
  if (!regex.global) {
    console.error('RegExp must have the global flag to retrieve multiple results.');
  }

  let match;
  while (match = regex.exec(str)) {
    yield match;
  }
}

const matches = execAll('a abbbbb no match ab', /\b(a)(b+)?\b/g);
for (const match of matches) {
  console.log(JSON.stringify(match));
  let otherProps = {};
  for (const [key, value] of Object.entries(match)) {
    if (isNaN(Number(key))) {
      otherProps[key] = value;
    }
  }
  
  console.log(otherProps);
}

ほとんどのJSプログラマーはプロトタイプを汚染することは悪い習慣だと考えていますが、これをに追加することもできますRegExp.prototype

if (RegExp.prototype.hasOwnProperty('execAll')) {
  console.error('RegExp prototype already includes a value for execAll.  Not overwriting it.');
} else {
  RegExp.prototype.execAll = 
    RegExp.prototype = function* execAll(str) {
      if (!this.global) {
        console.error('RegExp must have the global flag to retrieve multiple results.');
      }

      let match;
      while (match = this.exec(str)) {
        yield match;
      }
    };
}

const matches = /\b(a)(b+)?\b/g.execAll('a abbbbb no match ab');
console.log(Array.from(matches));

于 2021-02-01T17:47:29.300 に答える
0

ユーティリティ関数にカプセル化:

const regexExecAll = (str: string, regex: RegExp) => {
  let lastMatch: RegExpExecArray | null;
  const matches: RegExpExecArray[] = [];

  while ((lastMatch = regex.exec(str))) {
    matches.push(lastMatch);

    if (!regex.global) break;
  }

  return matches;
};

使用法:

const matches = regexExecAll("a a a", /(a)/g);

console.log(matches);

出力:

[
  [ 'a', 'a', index: 0, input: 'a a a', groups: undefined ],
  [ 'a', 'a', index: 2, input: 'a a a', groups: undefined ],
  [ 'a', 'a', index: 4, input: 'a a a', groups: undefined ]
]
于 2021-10-01T15:27:05.263 に答える