2013-02-13 7 views
10

Ich versuche alle möglichen Übereinstimmungen aus einem String mit javascript regex zu erhalten. Es scheint, dass meine Methode, dies zu tun, Teile der Zeichenfolge nicht übereinstimmen, die bereits abgeglichen wurden.Javascript Regex - Suche alle möglichen Übereinstimmungen, auch in bereits erfassten Spiele

Variablen:

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; 

Code:

var match = string.match(reg); 

Alle ich abgeglichen Resultate erhalten:

A1B1Y:A1B2Y 
A1B5Y:A1B6Y 
A1B9Y:A1B10Y 

Matched Ergebnisse Ich möchte:

A1B1Y:A1B2Y 
A1B2Y:A1B3Y 
A1B5Y:A1B6Y 
A1B6Y:A1B7Y 
A1B9Y:A1B10Y 
A1B10Y:A1B11Y 

In meinem Kopf möchte ich A1B1Y:A1B2Y, um ein Spiel zusammen mit A1B2Y:A1B3Y, obwohl A1B2Y in der Zeichenfolge muss Teil von zwei Übereinstimmungen sein.

+0

Ein Lookahead würde dir die gewünschten Matches liefern, aber leider liefert es nicht den Teil des Lookaheads. Ich habe keine Möglichkeit gefunden, den Lookahead mit Javascript zu erfassen. Vielleicht gibt es, weiß nicht. Ihre Regex mit Lookahead wäre: var reg =/A [0-9] + B [0-9] + Y (? =: A [0-9] + B [0-9] + Y)/g; – Someone

+0

@Mantriur: Siehe meine Antwort ... – nhahtdh

+0

Vielleicht 'string.split (": ")' und dann Schleife über das Array könnte Ihnen ein besseres Ergebnis geben. – Bergi

Antwort

20

Ohne die Regex zu ändern, können Sie festlegen, dass sie nach jeder Übereinstimmung am Anfang der zweiten Hälfte des Spiels mit .exec beginnt und die Eigenschaft lastIndex des Regex-Objekts bearbeitet.

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"] 

Demo


Per Bergi Kommentar, können Sie auch den Index des letzten Spiels erhalten und es erhöht um 1, so dass es statt ausgehend von der zweiten Hälfte des Spiel Spiel ab sie versuchen, wird es ab dem zweiten Zeichen jedes Spiel Spiel ab:

reg.lastIndex = found.index+1; 

Demo

Das Endergebnis ist das gleiche. Allerdings hat Bergis Update etwas weniger Code und führt leicht faster. =]

+0

Arbeitete, danke! –

+2

Schön, das ist viel besser als Lookahead, Capturing Groups usw. Btw, 'reg.lastIndex = found.index + 1;' sollte reichen und macht es ausdruck-agnostisch – Bergi

+0

@VinnieCent Kein Problem. '=]' Kreuze das V unter den Hoch/Runter-Pfeilen an, um es als akzeptiert zu markieren, wenn es für dich funktioniert hat. Oh, danke Bergi, war sich dieser Eigenschaft nicht bewusst. 'x]' –

4

Sie können nicht das direkte Ergebnis von match bekommen, aber es ist möglich, das Ergebnis über RegExp.exec und mit einigen Änderungen an die Regex zu produzieren:

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]); 
} 

I verwendet Null-Breite positiven Vorgriff (?=pattern), um den Text nicht zu konsumieren, so dass der überlappende Teil neu zugeordnet werden kann.

Eigentlich ist es möglich, replace Verfahren zu missbrauchen das gleiche Ergebnis zu tun erreichen:

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 ''; 
}); 

Da es jedoch replace ist, tut es besonders nutzlos Austauscharbeiten.

+0

Das hat auch funktioniert, danke! –

3

Leider ist es nicht ganz so einfach wie eine einzige string.match.

Der Grund ist, dass Sie überlappende Übereinstimmungen möchten, die das /g Flag Ihnen nicht gibt.

Sie könnten Look-Ahead verwenden:

var re = /A\d+B\d+Y(?=:A\d+B\d+Y)/g; 

Aber Sie jetzt bekommen:

string.match(re); // ["A1B1Y", "A1B2Y", "A1B5Y", "A1B6Y", "A1B9Y", "A1B10Y"] 

Der Grund dafür ist, dass Look-Ahead-Null-Breite ist, was bedeutet, dass es nur sagt, ob das Muster nach dem, was Sie kommt versuche zu passen oder nicht; Es enthält es nicht im Spiel.

Sie könnten exec verwenden, um zu versuchen und zu greifen, was Sie wollen. Wenn ein regulärer Ausdruck die /g Flagge hat, können Sie exec laufen immer wieder alle Spiele zu bekommen:

// 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" 
]; 

Here's a fiddle of this in action. Öffnen Sie die Konsole, um zu sehen, die Ergebnisse

Alternativ könnten Sie die ursprüngliche Zeichenfolge auf : aufgeteilt, dann die Schleife durch die resultierende Anordnung, Herausziehen der diejenigen, die passen, wenn array[i] und array[i+1] beide übereinstimmen, wie Sie möchten.

Verwandte Themen