Wie ersetze ich nur erfasste Gruppen?

192

Ich habe HTML-Code vor und nach der Zeichenfolge:

name="some_text_0_some_text"

Ich möchte das 0durch etwas ersetzen wie:!NEW_ID!

Also habe ich einen einfachen regulären Ausdruck gemacht:

.*name="\w+(\d+)\w+".*

Aber ich sehe nicht, wie ich ausschließlich den erfassten Block ersetzen soll.

Gibt es eine Möglichkeit, ein erfasstes Ergebnis wie ($ 1) durch eine andere Zeichenfolge zu ersetzen?

Das Ergebnis wäre:

name="some_text_!NEW_ID!_some_text"
Nicolas Guillaume
quelle

Antworten:

357

Eine Lösung besteht darin, Captures für den vorhergehenden und den folgenden Text hinzuzufügen:

str.replace(/(.*name="\w+)(\d+)(\w+".*)/, "$1!NEW_ID!$3")
Matthew Flaschen
quelle
75
Grüße aus der Zukunft! Ihre Lösung sieht wirklich ordentlich aus. Könnten Sie bitte Ihre Antwort erklären?
Polyducks
20
Die Klammern werden verwendet, um "Gruppen" zu erstellen, denen dann ein Basis-1-Index zugewiesen wird , auf den durch Ersetzen durch a $zugegriffen werden kann. Das erste Wort (\w+)befindet sich also in einer Gruppe und wird $1, der mittlere Teil (\d+)ist die zweite Gruppe (wird aber abgerufen) beim Ersetzen ignoriert), und die dritte Gruppe ist $3. Wenn Sie also die Ersetzungszeichenfolge von "$1!new_ID!$3"angeben, werden $ 1 und $ 3 automatisch durch die erste Gruppe und die dritte Gruppe ersetzt, sodass die zweite Gruppe durch die neue Zeichenfolge ersetzt werden kann, wobei der sie umgebende Text beibehalten wird.
mix3d
4
Obwohl ich verstehe, wie es funktioniert, hoffte ich auf eine elegantere Lösung>. <Trotzdem kann ich jetzt mit meinem Code weitermachen!
mix3d
9
1) Sie müssen nicht einmal \ d + erfassen. 2) Warum ist es Ihrer Meinung nach nicht elegant? Das Aufnehmen soll Sachen behalten, nicht wegwerfen. Was Sie behalten möchten, ist AROUND \ d +. Es ist also wirklich sinnvoll (und elegant genug), diese umgebenden Teile zu erfassen.
Sir4ur0n
3
Schöne Lösung. Was ist, wenn wir die Erfassungsgruppen anhand der Erfassungsgruppe als Grundlage für die Transformation ersetzen möchten? Gibt es dafür eine ebenso elegante Lösung? Derzeit speichere ich die erfassten Gruppen in einer Liste, schleife sie und ersetze die Erfassungsgruppe bei jeder Iteration durch den transformierten Wert
sookie
15

Jetzt, da Javascript (ab ES2018 ) anders aussieht , können Sie in neueren Umgebungen Gruppen in solchen Situationen vollständig vermeiden. Suchen Sie stattdessen nach dem, was vor der Gruppe kommt, die Sie erfasst haben, und suchen Sie nach dem, was kommt, und ersetzen Sie es durch nur !NEW_ID! :

const str = 'name="some_text_0_some_text"';
console.log(
  str.replace(/(?<=name="\w+)\d+(?=\w+")/, '!NEW_ID!')
);

Bei dieser Methode ist die vollständige Übereinstimmung nur der Teil, der ersetzt werden muss.

  • (?<=name="\w+)- Lookbehind for name", gefolgt von Wortzeichen (zum Glück müssen Lookbehinds in Javascript keine feste Breite haben!)
  • \d+ - Eine oder mehrere Ziffern abgleichen - der einzige Teil des Musters, der sich nicht in einem Lookaround befindet, der einzige Teil der Zeichenfolge, der in der resultierenden Übereinstimmung enthalten ist
  • (?=\w+")- Suchen Sie nach Wortzeichen, gefolgt von " `

Denken Sie daran, dass Lookbehind ziemlich neu ist. Es funktioniert in modernen Versionen von V8 (einschließlich Chrome, Opera und Node), aber noch nicht in den meisten anderen Umgebungen , zumindest noch nicht. Während Sie Lookbehind in Node und in Ihrem eigenen Browser zuverlässig verwenden können (wenn es auf einer modernen Version von V8 ausgeführt wird), wird es von zufälligen Clients (wie auf einer öffentlichen Website) noch nicht ausreichend unterstützt.

Bestimmte Leistung
quelle
Ich habe
Kaiido
Aber wenn ich zum Beispiel die Zahl multiplizieren und "zurücklegen" möchte, muss ich auch gruppieren \d+, oder?
Mosh Feu
@MoshFeu Verwenden Sie eine Ersetzungsfunktion und verwenden Sie die gesamte Übereinstimmung, die Ziffern: Ersetzen Sie den zweiten Parameter durch match => match * 2. Die Ziffern sind immer noch das ganze Spiel, daher sind keine Gruppen
erforderlich
Hab dich. Vielen Dank!
Mosh Feu
2

Eine kleine Verbesserung von Matthews Antwort könnte ein Lookahead anstelle der letzten Erfassungsgruppe sein:

.replace(/(\w+)(\d+)(?=\w+)/, "$1!NEW_ID!");

Oder Sie können auf der Dezimalstelle teilen und sich wie folgt mit Ihrer neuen ID verbinden:

.split(/\d+/).join("!NEW_ID!");

Beispiel / Benchmark hier: https://codepen.io/jogai/full/oyNXBX

Jogai
quelle
1

Mit zwei Erfassungsgruppen wäre auch möglich gewesen; Ich hätte auch zwei Striche als zusätzliche linke und rechte Grenze vor und nach den Ziffern eingefügt, und der modifizierte Ausdruck hätte wie folgt ausgesehen:

(.*name=".+_)\d+(_[^"]+".*)

const regex = /(.*name=".+_)\d+(_[^"]+".*)/g;
const str = `some_data_before name="some_text_0_some_text" and then some_data after`;
const subst = `$1!NEW_ID!$2`;
const result = str.replace(regex, subst);
console.log(result);


Wenn Sie den Ausdruck untersuchen / vereinfachen / ändern möchten, wurde dies im oberen rechten Bereich von regex101.com erläutert . Wenn Sie möchten , können Sie in diesem Link auch sehen , wie es mit einigen Beispieleingaben übereinstimmt.


RegEx Circuit

jex.im visualisiert reguläre Ausdrücke:

Geben Sie hier die Bildbeschreibung ein

Emma
quelle
0

Eine einfachere Möglichkeit besteht darin, nur die Ziffern zu erfassen und zu ersetzen.

const name = 'preceding_text_0_following_text';
const matcher = /(\d+)/;

// Replace with whatever you would like
const newName = name.replace(matcher, 'NEW_STUFF');
console.log("Full replace", newName);

// Perform work on the match and replace using a function
// In this case increment it using an arrow function
const incrementedName = name.replace(matcher, (match) => ++match);
console.log("Increment", incrementedName);

Ressourcen

CTS_AE
quelle