JavaScript zamień / wyrażenie regularne

113

Biorąc pod uwagę tę funkcję:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

Jak dokonać this.markup.replace()wymiany na całym świecie? Oto problem. Jeśli używam go w ten sposób:

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

Wartość alertu to „foobar $ TEST_ONE”.

Jeśli zmienię Repeaterna następujące, nic nie zostanie zastąpione w Chrome:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

... a alert jest $TEST_ONE $TEST_ONE.

rdzeń
źródło

Odpowiedzi:

147

Musisz podwójnie zmienić znaczenie wszystkich znaków RegExp (raz dla ukośnika w ciągu i raz dla wyrażenia regularnego):

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

W przeciwnym razie szuka końca linii i „TESTONE” (którego nigdy nie znajdzie).

Osobiście nie jestem wielkim fanem budowania wyrażeń regularnych przy użyciu ciągów z tego powodu. Wymagany poziom ucieczki może doprowadzić do picia. Jestem pewien, że inni czują się inaczej i lubią pić podczas pisania wyrażeń regularnych.

seth
źródło
Ale replace () otrzymuje wyrażenie regularne jako zmienną.
rdzeń
8
@Chris - nie sądzę, aby miało to znaczenie, jeśli używasz /pattern/lub new RegExp("pattern").
harto
@seth, Twoja odpowiedź działa, ale nie dostarcza rozwiązania dla kodu z OP. Jak mam zadzwonić na kod OP?
Czarny
82

Pod względem interpretacji wzorców nie ma różnicy między następującymi formami:

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

Jeśli chcesz zamienić dosłowny ciąg przy użyciu tej replacemetody, myślę, że możesz po prostu przekazać ciąg zamiast wyrażenia regularnego do replace.

W przeciwnym razie musiałbyś najpierw uciec od wszelkich znaków specjalnych wyrażenia regularnego we wzorcu - może tak:

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

// ...

var re = new RegExp(reEscape(pattern), "mg");
this.markup = this.markup.replace(re, value);
Harto
źródło
12
Nie wiedziałem wcześniej, że / wzorzec / jest tym samym, co nowe wyrażenie RegExp („wzorzec”). Naprawdę pomogło!
Nik Sumeiko
1
Jest jakiś powód, aby nie używać białej listy zamiast czarnej listy? np .: s.replace (/ (\ W) / g, '\\ $ 1')
greg.kindel
1
Pierwsza wymieniona forma jest lepsza. Dobrą praktyką jest unikanie nowego słowa kluczowego.
Druska
2
Nie jest dokładne stwierdzenie, że literał wyrażenia regularnego (/ regex /) jest taki sam jak wyrażenie RegExp („regex”). W dosłownym wyrażeniu regularnym solidus reverse-solidus ('\') nie musi być sam w sobie znakowany znakiem ucieczki ('\\'), aby stał się częścią wyrażenia regularnego. Co więcej, literał wyrażenia regularnego można skompilować, gdy skrypt jest analizowany, a nie za każdym razem, gdy funkcja jest wykonywana. Aby dopasować odwrotny solidus, możesz napisać / \\ / lub RexExp ("\\\\").
John
31

Twój wzorzec wyrażenia regularnego powinien mieć modyfikator g:

var pattern = /[somepattern]+/g;

zwróć uwagę na g na końcu. nakazuje zamiennikowi wykonanie globalnej zamiany.

Nie musisz też używać obiektu RegExp, możesz skonstruować wzorzec jak powyżej. Przykładowy wzór:

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

wzorzec jest zawsze otoczony przez / z każdej strony - z modyfikatorami po ostatnim /, przy czym modyfikator g jest globalny.

EDYCJA: Dlaczego ma znaczenie, czy wzorzec jest zmienną? W twoim przypadku działałoby to tak (zauważ, że wzorzec jest nadal zmienną):

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

Ale musiałbyś zmienić swoją funkcję zamiany na następującą:

this.markup = this.markup.replace(pattern, value);
Darko Z
źródło