web-dev-qa-db-fra.com

Comment remplacer uniquement les groupes capturés?

J'ai du code HTML avant et après la chaîne:

name="some_text_0_some_text"

Je voudrais remplacer le 0 par quelque chose comme: !NEW_ID!

Alors j'ai fait une regex simple:

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

Mais je ne vois pas comment remplacer exclusivement le bloc capturé.

Existe-t-il un moyen de remplacer un résultat capturé, tel que ($ 1), par une autre chaîne?

Le résultat serait:

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

Une solution consiste à ajouter des captures pour le texte précédent et suivant:

str.replace(/(.*name="\w+)(\d+)(\w+".*)/, "$1!NEW_ID!$3")
289
Matthew Flaschen

Maintenant que Javascript a regardé (à partir de ES2018 ), sur les environnements plus récents, vous pouvez éviter complètement les groupes dans de telles situations. Recherchez plutôt ce qui précède le groupe que vous capturiez et attendez après, et remplacez-le par simplement !NEW_ID!:

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

Avec cette méthode, la correspondance complète est seulement la pièce à remplacer.

  • (?<=name="\w+) - Lookbehind pour name", suivi de caractères Word (heureusement, il n’est pas nécessaire de fixer la largeur en Javascript!)
  • \d+ - Correspond à un ou plusieurs chiffres - la seule partie du motif qui ne figure pas dans une apparence, la seule partie de la chaîne qui figurera dans la correspondance résultante.
  • (?=\w+") - Rechercher des caractères Word suivis de " `

Gardez à l'esprit que le lookbehind est assez nouveau. Cela fonctionne dans les versions modernes de V8 (y compris Chrome, Opera et Node), mais pas dans la plupart des autres environnements , du moins pas encore. Ainsi, bien que vous puissiez utiliser de manière fiable lookbehind dans Node et dans votre propre navigateur (s'il fonctionne sur une version moderne de V8), il n'est pas encore suffisamment pris en charge par des clients aléatoires (comme sur un site Web public). .

2
CertainPerformance

Une petite amélioration par rapport à la réponse de Matthew pourrait être un look au lieu du dernier groupe de capture:

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

Ou vous pouvez séparer le nombre décimal et rejoindre votre nouvel identifiant comme ceci:

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

Exemple/référence ici: https://codepen.io/jogai/full/oyNXBX

1
Jogai

Une option plus simple consiste à capturer les chiffres et à les remplacer.

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

Ressources

0
CTS_AE

Avec deux groupes de capture aurait également été possible; J'aurais également inclus deux tirets, en tant que limites gauche et droite supplémentaires, avant et après les chiffres, et l'expression modifiée aurait ressemblé à:

(.*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);

Si vous souhaitez explorer/simplifier/modifier l'expression, cela a été expliqué dans le panneau en haut à droite de regex101.com . Si vous le souhaitez, vous pouvez également regarder dans ce lien , comment cela correspondrait avec certains exemples d'entrées.


Circuit RegEx

jex.im visualise les expressions régulières:

enter image description here

0
Emma