Заміна JavaScript / регекс


113

З огляду на цю функцію:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

Як зробити this.markup.replace()заміну в усьому світі? Ось проблема. Якщо я використовую його так:

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

Значення сповіщення - "foobar $ TEST_ONE".

Якщо я перейду Repeaterдо наступного, у Chrome нічого не замінено:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

... і оповіщення є $TEST_ONE $TEST_ONE.

Відповіді:


147

Вам потрібно подвоїти будь-які символи RegExp (один раз для косої риски в рядку і один раз для regexp):

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

В іншому випадку він шукає кінець рядка та "TESTONE" (який він ніколи не знаходить).

Особисто я не є великим прихильником того, щоб будувати regexp, використовуючи рядки з цієї причини. Рівень втечі, який необхідний, може змусити вас пити. Я впевнений, що інші відчувають себе по-іншому і люблять пити, коли пишуть регулярні виразки.


Але замінити () отримує регулярний вираз у вигляді змінної.
серцевина

8
@Chris - я не думаю, що це має значення, якщо ви використовуєте /pattern/або new RegExp("pattern").
harto

@seth, Ваша відповідь працює, але це не забезпечує рішення коду з ОП. Як мені потрібно викликати код ОП?
Чорний

82

Що стосується інтерпретації шаблонів, то різниці між такими формами немає:

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

Якщо ви хочете замінити буквальну рядок за допомогою replaceметоду, я думаю, ви можете просто передати рядок замість регулярного переходу до replace.

В іншому випадку вам доведеться спочатку уникнути будь-яких спеціальних символів для регулярного виразів у шаблоні - можливо, так:

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

// ...

var re = new RegExp(reEscape(pattern), "mg");
this.markup = this.markup.replace(re, value);

12
Раніше не знав, що / pattern / - це те саме, що і новий RegExp ("pattern"). Дійсно допомогли!
Нік Сумейко

1
Будь-яка причина не використовувати білий список замість чорного списку? наприклад: s.replace (/ (\ W) / g, '\\ $ 1')
greg.kindel

1
Перша перерахована форма - краще. Добра практика уникати нового ключового слова.
Друська

2
Не точно сказати, що літеральний регулярний вираз (/ regex /) такий же, як RegExp ("regex"). У прямому виразі регулярного виразу зворотний солідус ('\') сам по собі не повинен бути уникнутим ('\\'), щоб він був частиною регулярного виразу. Крім того, регулярний літеральний вираз може бути складений під час розбору сценарію, а не кожного разу, коли виконується функція. Для того, щоб відповідати зворотному солідусу, ви можете написати / \\ / або RexExp ("\\\\").
Іван

31

Ваш шаблон регулярного вираження повинен мати модифікатор g:

var pattern = /[somepattern]+/g;

помітьте г в кінці. він вказує замінювачу зробити глобальну заміну.

Крім того, вам не потрібно використовувати об'єкт RegExp, ви можете побудувати свій візерунок як вище. Приклад шаблону:

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

шаблон завжди оточений / з обох боків - з модифікаторами після остаточного /, модифікатор g - глобальний.

EDIT: Чому це важливо, якщо шаблон є змінною? У вашому випадку це буде функціонувати так (зауважте, що шаблон все ще є змінною):

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

Але вам потрібно змінити функцію заміни на цю:

this.markup = this.markup.replace(pattern, value);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.