2016-03-21 15 views
4

sagen, dass ich einen String haben, wie:single js regex für passende Wiederholungs-Teilstrings?

where is mummy where is daddy 

ich eine Reihe von sich wiederholenden Teil mit leeren Zeichenfolgen ersetzt werden soll - in diesem Fall also die where und is Elemente und die resultierende Zeichenfolge würde entfernt werden würde:

mummy daddy 

Ich fragte mich, ob es eine einzige Regex, die dies erreichen könnte. Die Regex Ich habe versucht, sah (was nicht funktioniert) wie folgt aus:

/(\w+)(?=.*)\1/gi 

Wo die erste Fanggruppe ist jede Gruppe von Wortzeichen, das zweite ist ein positiver Ausblick auf jede Gruppe von Zeichen (in der Reihenfolge um zu verhindern, dass diese Zeichen im Ergebnis enthalten sind) und dann ist \1 eine Rückreferenz für die erste übereinstimmende Teilzeichenkette.

Jede Hilfe wäre großartig. Danke im Voraus!

+1

Wiederholte Wörter sind behoben oder möchten Sie wiederholte Wörter zuerst herausfinden und dann ersetzen? – gurvinder372

+2

Vielleicht ['(\ b \ w + \ b) (? =. * \ 1)'] (https://regex101.com/r/nY3sO4/1)? –

+0

@ gurvinder372 Finden Sie wiederholte Wörter zuerst und ersetzen Sie sie dann nehme ich an - ich fragte mich, ob es einen einzigen Regex gab, der das erreichen konnte –

Antwort

6

Ihre Regex funktioniert nicht, weil die \w+ nicht mit Wortgrenzen und die \1 beschränkt Rückreferenzierung wird versucht, direkt nach dem „Original“ Wort übereinstimmen, was wahr fast nie ist.

Sie müssen zuerst die Worte zu bekommen, die Betrogenen sind, und dann ein RegExp bauen sie alle mit optionalen Leerzeichen übereinstimmen (oder Zeichensetzung, usw. - später das Muster anzupassen) und ersetzen mit einem leeren String:

var re = /(\b\w+\b)(?=.*\b\1\b)/gi;     // Get the repeated whole words 
 
var str = 'where is mummy where is daddy'; 
 
var patts = str.match(re);      // Collect the matched repeated words 
 
var res = str.replace(RegExp("\\s*\\b(?:" + patts.join("|") +")\\b", "gi"), ""); // Build the pattern for replacing all found words 
 
document.body.innerHTML = res;

Das erste Muster ist (\b\w+\b)(?=.*\b\1\b):

  • (\b\w+\b) - passen ein d Erfassen Sie in Gruppe 1 ein ganzes Wort bestehend aus [A-Za-z0-9_] Zeichen
  • (?=.*\b\1\b) - stellen Sie sicher, dass dieser in Gruppe 1 erfasste Wert irgendwo rechts von der aktuellen Position (nicht unbedingt gleich nach dem Wort) wiederholt wird. Wenn die Zeichenfolge multiline ist, verwenden Sie anstelle des Punkts [\s\S]. Um sicherzustellen, dass Original- und Duplizierwörter als ganze Wörter übereinstimmen, sollten \b Wortgrenzen sowohl für \w+ als auch für \1 verwendet werden.

Das zweite Muster wird jedes Mal anders aussehen, aber in der aktuellen Szenario, wird es /\s*\b(?:where|is)\b/gi:

  • \s* - null oder mehr whitepsace
  • \b(?:where|is)\b - ein ganzes Wort aus dem Wechsel Gruppe (?:...|...): entweder where oder is (case-insensitive aufgrund /i Modifizierer).
+2

Große Antwort! Beim Spielen mit deinem Code bin ich auf ein überraschendes Problem gestoßen. Es scheint, dass die Überprüfungen der Wortgrenzen nicht Teil der ersten Erfassungsgruppe sind. Daher, wenn Sie es auf der Zeichenfolge "wo ist meine Mama, wo ist Papa" das Wort "mein" ist auch gelöscht, weil es in "Mumie" erscheint. Um falsche Positive zu vermeiden, müssen Sie die Checks für die Wortgrenzen um die Wiederholung der ersten Capture-Gruppe erneut hinzufügen (var re = /(\b\w+\b)(?=.*\b\1\b)/gi). –

+0

Ja, Sie brauchen dann auch die Wortgrenzen um die Rückreferenz, sonst ist die Wortüberprüfung nicht korrekt. Ich habe die Antwort aktualisiert, um diesen Aspekt wiederzugeben. –

+0

Sehr informativ. Vielen Dank, Wiktor –