Ganti JavaScript / regex

113

Diberikan fungsi ini:

function Repeater(template) {

    var repeater = {

        markup: template,

        replace: function(pattern, value) {
            this.markup = this.markup.replace(pattern, value);
        }

    };

    return repeater;

};

Bagaimana cara saya melakukan this.markup.replace()penggantian secara global? Inilah masalahnya. Jika saya menggunakannya seperti ini:

alert(new Repeater("$TEST_ONE $TEST_ONE").replace("$TEST_ONE", "foobar").markup);

Nilai lansiran adalah "foobar $ TEST_ONE".

Jika saya mengubah Repeaterke yang berikut, maka tidak ada yang diganti di Chrome:

function Repeater(template) {

    var repeater = {

        markup: template,

        replace: function(pattern, value) {
            this.markup = this.markup.replace(new RegExp(pattern, "gm"), value);
        }

    };

    return repeater;

};

... dan peringatannya adalah $TEST_ONE $TEST_ONE.

inti
sumber

Jawaban:

147

Anda perlu meloloskan diri dari karakter RegExp dua kali (sekali untuk garis miring di string dan satu kali untuk ekspresi reguler):

  "$TESTONE $TESTONE".replace( new RegExp("\\$TESTONE","gm"),"foo")

Jika tidak, itu mencari akhir baris dan 'TESTONE' (yang tidak pernah ditemukan).

Secara pribadi, saya bukan penggemar berat membangun regexp menggunakan string karena alasan ini. Tingkat melarikan diri yang dibutuhkan bisa membuat Anda minum. Saya yakin orang lain merasa berbeda dan suka minum saat menulis ekspresi reguler.

seth
sumber
Tapi replace () menerima regex sebagai variabel.
inti
8
@ Chris - Saya rasa tidak ada bedanya jika Anda menggunakan /pattern/atau new RegExp("pattern").
harto
@ seth, Jawaban Anda berfungsi, tetapi tidak memberikan solusi untuk kode dari OP. Bagaimana saya harus memanggil kode OP?
Hitam
82

Dalam hal interpretasi pola, tidak ada perbedaan antara bentuk-bentuk berikut:

  • /pattern/
  • new RegExp("pattern")

Jika Anda ingin mengganti string literal menggunakan replacemetode ini, saya pikir Anda bisa meneruskan string alih-alih regexp ke replace.

Jika tidak, Anda harus melepaskan karakter khusus regexp dalam pola terlebih dahulu - mungkin seperti ini:

function reEscape(s) {
    return s.replace(/([.*+?^$|(){}\[\]])/mg, "\\$1");
}

// ...

var re = new RegExp(reEscape(pattern), "mg");
this.markup = this.markup.replace(re, value);
harto
sumber
12
Tidak tahu sebelumnya, bahwa / pattern / sama dengan RegExp baru ("pattern"). Sangat membantu!
Nik Sumeiko
1
Ada alasan untuk tidak menggunakan daftar putih daripada daftar hitam? misalnya: s.replace (/ (\ W) / g, '\\ $ 1')
greg.kindel
1
Bentuk pertama yang terdaftar lebih baik. Ini praktik yang baik untuk menghindari kata kunci baru .
Druska
2
Tidak akurat untuk mengatakan bahwa ekspresi reguler literal (/ regex /) sama dengan RegExp ("regex"). Dalam ekspresi reguler literal, reverse-solidus ('\') tidak perlu di-escape sendiri ('\\') agar bisa menjadi bagian dari ekspresi reguler. Lebih lanjut, literal ekspresi reguler dapat dikompilasi saat skrip diurai daripada setiap kali fungsi dijalankan. Untuk mencocokkan reverse-solidus Anda bisa menulis / \\ / atau RexExp ("\\\\").
Yohanes
31

Pola regex Anda harus memiliki pengubah g:

var pattern = /[somepattern]+/g;

perhatikan g di bagian akhir. itu memberi tahu pengganti untuk melakukan penggantian global.

Anda juga tidak perlu menggunakan objek RegExp, Anda dapat membuat pola seperti di atas. Contoh pola:

var pattern = /[0-9a-zA-Z]+/g;

sebuah pola selalu diapit oleh / di kedua sisi - dengan pengubah setelah akhir /, pengubah g menjadi global.

EDIT: Mengapa penting jika pola adalah variabel? Dalam kasus Anda, ini akan berfungsi seperti ini (perhatikan bahwa pola masih berupa variabel):

var pattern = /[0-9a-zA-Z]+/g;
repeater.replace(pattern, "1234abc");

Tapi Anda perlu mengubah fungsi replace Anda menjadi ini:

this.markup = this.markup.replace(pattern, value);
Darko Z
sumber