私は、JavaScriptで正規表現を使用して文字列から可能なすべての一致を取得しようとしています。これを行う私の方法は、すでに一致している文字列の一部と一致していないようです。
変数:
var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y';
var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g;
コード:
var match = string.match(reg);
私が得るすべての一致した結果:
A1B1Y:A1B2Y
A1B5Y:A1B6Y
A1B9Y:A1B10Y
一致する結果が欲しい:
A1B1Y:A1B2Y
A1B2Y:A1B3Y
A1B5Y:A1B6Y
A1B6Y:A1B7Y
A1B9Y:A1B10Y
A1B10Y:A1B11Y
頭の中では、文字列のA1B1Y:A1B2Y
が2つの一致の一部である必要がある場合でも、A1B2Y:A1B3Y
をA1B2Y
と一致させたいと思います。
正規表現を変更せずに、 .exec
を使用し、正規表現オブジェクトのlastIndex
プロパティを操作して、各一致の後に一致の後半の開始時に一致を開始するように設定できます。
var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y';
var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g;
var matches = [], found;
while (found = reg.exec(string)) {
matches.Push(found[0]);
reg.lastIndex -= found[0].split(':')[1].length;
}
console.log(matches);
//["A1B1Y:A1B2Y", "A1B2Y:A1B3Y", "A1B5Y:A1B6Y", "A1B6Y:A1B7Y", "A1B9Y:A1B10Y", "A1B10Y:A1B11Y"]
Bergiのコメントによると、最後のマッチのインデックスを取得して1ずつ増やすこともできるので、マッチの後半からマッチを開始する代わりに、各マッチの2番目のキャラクターからマッチを開始します。 :
reg.lastIndex = found.index+1;
最終的な結果は同じです。ただし、Bergiのアップデートはコードが少し少なく、わずかに 速い を実行します。 =]
match
から直接の結果を取得することはできませんが、RegExp.exec
を介して、正規表現にいくつかの変更を加えて結果を生成することは可能です。
var regex = /A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g;
var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'
var arr;
var results = [];
while ((arr = regex.exec(input)) !== null) {
results.Push(arr[0] + arr[1]);
}
私はzero-widthポジティブルックアヘッド(?=pattern)
を使用して、テキストを消費しないようにし、重複部分を再照合できるようにしました。
実際、replace
メソッドを悪用して同じ結果を得ることができます。
var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'
var results = [];
input.replace(/A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g, function ($0, $1) {
results.Push($0 + $1);
return '';
});
ただし、replace
であるため、余分な無駄な置換作業が行われます。
残念ながら、それは単一のstring.match
ほど単純ではありません。
その理由は、/g
フラグでは得られない、重複する一致が必要なためです。
あなたは先読みを使うことができます:
var re = /A\d+B\d+Y(?=:A\d+B\d+Y)/g;
しかし今あなたは得る:
string.match(re); // ["A1B1Y", "A1B2Y", "A1B5Y", "A1B6Y", "A1B9Y", "A1B10Y"]
その理由は、先読みは幅がゼロであるためです。つまり、パターンが、一致させようとしているものの後に来るかどうかを示すだけです。試合には含まれません。
exec
を使用して、必要なものを取得できます。正規表現に/g
フラグがある場合、exec
を繰り返し実行して、すべての一致を取得できます。
// using re from above to get the overlapping matches
var m;
var matches = [];
var re2 = /A\d+B\d+Y:A\d+B\d+Y/g; // make another regex to get what we need
while ((m = re.exec(string)) !== null) {
// m is a match object, which has the index of the current match
matches.Push(string.substring(m.index).match(re2)[0]);
}
matches == [
"A1B1Y:A1B2Y",
"A1B2Y:A1B3Y",
"A1B5Y:A1B6Y",
"A1B6Y:A1B7Y",
"A1B9Y:A1B10Y",
"A1B10Y:A1B11Y"
];
これは実際のフィドルです 。コンソールを開いて結果を確認します
または、:
で元の文字列を分割し、結果の配列をループして、array[i]
とarray[i+1]
の両方が一致する場合に一致するものを引き出します。