私が走るとき
/(a)/g.exec('a a a ').length
私は得る
2
でも戻るべきだと思った
3
a
文字列には2ではなく3が含まれているためです。
何故ですか?
RegExで文字列のすべての出現箇所を検索し、それらを反復処理できるようにしたいと思います。
FWIW:node.jsを使用しています
私が走るとき
/(a)/g.exec('a a a ').length
私は得る
2
でも戻るべきだと思った
3
a
文字列には2ではなく3が含まれているためです。
何故ですか?
RegExで文字列のすべての出現箇所を検索し、それらを反復処理できるようにしたいと思います。
FWIW:node.jsを使用しています
exec()
は、最初の一致のキャプチャのセットのみを返し、期待どおりの一致のセットは返しません。つまり、実際に表示されている$0
のは、(一致全体、「a」)と$1
(最初のキャプチャ)、つまり長さ2の配列です。 一方、次の一致のキャプチャを取得するために再度exec()
呼び出すことができるように設計されています。 。MDNから:
正規表現で「g」フラグを使用している場合は、execメソッドを複数回使用して、同じ文字列内の連続する一致を見つけることができます。これを行うと、検索は正規表現のlastIndexプロパティで指定されたstrのサブストリングから開始されます(テストはlastIndexプロパティも進めます)。
代わりに使用できますmatch
:
'a a a'.match(/(a)/g).length // outputs: 3
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の文字列からすべての値をループして取得する方法を説明することです。
最初のaのみを一致させます。長さが2である理由は、最初の一致と最初の一致の括弧で囲まれたグループ部分を検索しているためです。あなたの場合、それらは同じです。
この例を考えてみましょう。
var a = /b(a)/g.exec('ba ba ba ');
alert(a);
を出力しますba, a
。配列の長さはまだ2ですが、何が起こっているのかがより明確になります。「ba」は完全一致です。 a
括弧で囲まれた最初のグループ化の一致です。
MDNドキュメントはこれをサポートしています-最初の一致と含まれているグループのみが返されます。すべての一致を見つけるには、mVChrで指定されているようにmatch()を使用します。
コード:
alert('a a a'.match(/(a)/g).length);
出力:
3
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);
}
すでにいくつかの答えがありますが、不必要に複雑です。結果の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);
}
あなたの例で.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));
ユーティリティ関数にカプセル化:
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 ]
]