Bagaimana cara mengganti grup yang ditangkap saja?

196

Saya punya kode HTML sebelum dan sesudah string:

name="some_text_0_some_text"

Saya ingin mengganti 0dengan sesuatu seperti:!NEW_ID!

Jadi saya membuat regex sederhana:

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

Tetapi saya tidak melihat bagaimana cara mengganti secara eksklusif blok yang ditangkap.

Apakah ada cara untuk mengganti hasil yang diambil seperti ($ 1) oleh beberapa string lain?

Hasilnya adalah:

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

Jawaban:

359

Solusinya adalah dengan menambahkan tangkapan untuk teks sebelumnya dan berikut:

str.replace(/(.*name="\w+)(\d+)(\w+".*)/, "$1!NEW_ID!$3")
Matthew Flaschen
sumber
76
Salam dari masa depan! Solusi Anda terlihat sangat rapi. Bisakah Anda jelaskan jawaban Anda?
Polyducks
21
Tanda kurung digunakan untuk membuat "grup", yang kemudian ditugaskan indeks basis-1, dapat diakses di ganti dengan $, jadi kata pertama (\w+)adalah dalam grup, dan menjadi $1, bagian tengah (\d+)adalah grup kedua, (tetapi mendapat diabaikan di ganti), dan kelompok ketiga adalah $3. Jadi, ketika Anda memberikan string pengganti "$1!new_ID!$3", $ 1 dan $ 3 diganti secara otomatis dengan grup pertama dan grup ketiga, memungkinkan grup kedua diganti dengan string baru, dengan mempertahankan teks yang mengelilinginya.
mix3d
4
Yang sedang berkata, sementara saya mengerti BAGAIMANA berhasil, saya berharap untuk solusi yang lebih elegan>. <Namun, saya dapat bergerak maju dengan kode saya sekarang!
mix3d
9
1) Anda bahkan tidak perlu menangkap \ d + 2) Mengapa Anda mengatakan itu tidak elegan? Menangkap dimaksudkan untuk menyimpan barang, bukan membuangnya. Yang ingin Anda pertahankan adalah apa yang SEKITAR \ d +, jadi sangat masuk akal (dan cukup elegan) untuk menangkap bagian-bagian di sekitarnya.
Sir4ur0n
3
Solusi bagus Bagaimana jika kita ingin mengganti kelompok tangkap menggunakan kelompok tangkap sebagai dasar untuk transformasi? Apakah ada solusi yang sama-sama elegan untuk melakukan ini? Saat ini saya menyimpan grup yang ditangkap dalam daftar, mengulanginya, dan mengganti grup yang ditangkap dengan nilai yang diubah di setiap iterasi
sookie
15

Sekarang Javascript telah terlihat di belakang (pada ES2018 ), pada lingkungan yang lebih baru, Anda dapat menghindari grup sepenuhnya dalam situasi seperti ini. Alih-alih, lihat di belakang apa yang datang sebelum kelompok yang Anda tangkap, dan cari yang akan datang setelahnya, dan ganti dengan yang baru !NEW_ID! :

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

Dengan metode ini, pertandingan penuh hanya bagian yang perlu diganti.

  • (?<=name="\w+)- Cari di belakang name", diikuti oleh karakter kata (untungnya, lookbehinds tidak harus diperbaiki lebar dalam Javascript!)
  • \d+ - Cocokkan satu atau lebih digit - satu-satunya bagian dari pola yang tidak terlihat, satu-satunya bagian dari string yang akan ada dalam pertandingan yang dihasilkan
  • (?=\w+")- Cari karakter kata yang diikuti oleh " `

Perlu diingat bahwa tampilan di belakang cukup baru. Ini berfungsi dalam versi modern V8 (termasuk Chrome, Opera, dan Node), tetapi tidak di sebagian besar lingkungan lain , setidaknya belum. Jadi, meskipun Anda dapat menggunakan lookbehind di Node dan di browser Anda sendiri (jika berjalan pada versi modern V8), itu belum didukung oleh klien acak (seperti di situs web publik).

Performa Tertentu
sumber
Hanya menjalankan tes waktu cepat, dan itu sangat mengesankan bagaimana input penting: jsfiddle.net/60neyop5
Kaiido
Tetapi jika, misalnya saya ingin mengekstraksi angka, banyak dan "mengembalikannya", saya harus mengelompokkan juga \d+, kan?
Mosh Feu
@MoshFeu Gunakan fungsi replacer dan gunakan seluruh kecocokan, digit: ganti parameter kedua dengan match => match * 2. Digit masih merupakan keseluruhan pertandingan, jadi tidak perlu untuk grup
Performa Tertentu
Kena kau. Terima kasih!
Mosh Feu
2

Sedikit perbaikan pada jawaban Matius bisa menjadi pengintai alih-alih kelompok penangkapan terakhir:

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

Atau Anda dapat membagi desimal dan bergabung dengan id baru Anda seperti ini:

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

Contoh / Tolok Ukur di sini: https://codepen.io/jogai/full/oyNXBX

Jogai
sumber
1

Dengan dua kelompok penangkap juga dimungkinkan; Saya juga akan menyertakan dua tanda hubung, sebagai batas kiri dan kanan tambahan, sebelum dan setelah angka, dan ekspresi yang dimodifikasi akan terlihat seperti:

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


Jika Anda ingin menjelajahi / menyederhanakan / memodifikasi ekspresi, sudah dijelaskan di panel kanan atas regex101.com . Jika mau, Anda juga dapat menonton di tautan ini , bagaimana itu cocok dengan beberapa input sampel.


Sirkuit RegEx

jex.im memvisualisasikan ekspresi reguler:

masukkan deskripsi gambar di sini

Emma
sumber
0

Opsi yang lebih sederhana adalah dengan hanya menangkap digit dan menggantinya.

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

Sumber daya

CTS_AE
sumber