2015-08-11 2 views
5

У меня есть строка, что я пытаюсь манипулировать, используя регулярное выражение следующим образом:RegExp Exec - строка манипуляции

var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', 
    reg = /{{.*?}}/ig; 

while (field = reg.exec(str)) { 
    str = str.replace(field, 'test'); 
} 

{{param2}} никогда не заменяется, хотя - я думаю, потому что я манипулируя строку во время работы его через RegExp.exec(...). Но не может быть уверен.

Я попробовал следующее (как я заметил, RegExp.exec(...) возвращает массив) - еще не повезло:

var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', 
    reg = /{{.*?}}/ig; 

while (field = reg.exec(str)) { 
    str = str.replace(field[0], 'test'); 
} 

Любые идеи?

Edit: текущий результат этой функции:

'This is a string with 1: test, 2: {{param2}}, test and 3: test' 
+0

Вам нужно избежать этих фигурных скобок в вашем шаблоне регулярных выражений. –

+0

Спасибо - не работает, я боюсь – keldar

+0

Кроме того, 'i' здесь не имеет смысла. –

ответ

3

Вы должны удалить g флаг.

var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', 
    reg = /{{.*?}}/; 



while (field = reg.exec(str)) { 
    str = str.replace(field, 'test'); 
    console.log(str) 
} 

Результат:

первой итерации:

Это строка с 1: тест, 2: {{param2}} и 3: {{param3}}

Во-вторых:

Это строка с 1: тест, 2: Испытание и 3: {{param3}}

третий:

Это строка с 1: тест, 2: испытание и 3: Испытание

Другой вариант сделать:

str = str.replace(/{{.*?}}/g, 'test'); 

Это будет также выход:

Это строка 1: тест, 2: испытания и 3: тест

Edit:

Чтобы добавить ответ Anonymous в:

Проблема заключается в том, что каждый replace - делает исходную строку короче. Индексы были рассчитаны на начиная с с оригинальной более длинной строкой.

Другими словами, если бы вы хотели заменить на то же выражение длины, как {{param1}} (что это длина 9), на другую строку с той же длиной 9, скажем: **test1**, то ваш код работал бы:

var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', 
    reg = /{{.*?}}/g 


while (field = reg.exec(str)) { 

    str = str.replace(field, '**test1**'); 
    console.log(str) 
} 

Результат:

This is a string with 1: **test1**, 2: **test1** and 3: **test1**

+0

Ницца! Спасибо. Я не думаю, что вы можете объяснить, почему он не работает с глобальным флагом? – keldar

+0

Или вы можете сохранить флаг 'g' и выровнять цикл while while (сохраните замену, хотя и заменив в' reg' для 'field'). –

0

Вы правильно. Из-за замены его едва хватает. Ниже приводится порядок выполнения регулярных выражений:

  • После первого Exec, reg.lastIndex установлен на 35.
  • остальные строки для проверки становится ', 2: {{param2}} and 3: {{param3}}'
  • После первой замены, остальные строка для соответствия становится '{param2}} and 3: {{param3}}' с lastIndex не изменяется от 35
  • следующая итерация регулярных выражений происходит, но это не соответствует {param2}}, поэтому он не поддерживает согласование до достижения '{{param3}}'.

Все это происходит потому, что флаг g lobal regex сохраняет lastIndex. Вместо этого вы можете удалить глобальный флаг, чтобы автоматически установить lastIndex на 0 после окончания одного совпадения. Однако это означает, что регулярное выражение всегда будет начинаться с начала. Лучшим вариантом является установка lastIndex в нужное положение.

var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', 
 
    reg = /{{.*?}}/ig, 
 
    replacement = 'test'; 
 

 
while (field = reg.exec(str)) { 
 
    str = str.replace(field[0], replacement); 
 
    reg.lastIndex = reg.lastIndex - field[0].length + replacement.length; 
 
} 
 
console.log(str);

+0

Не знал, что существует свойство 'lastIndex' - наиболее полезно для отладки! Благодарю. – keldar

+0

Нет проблем. Рад, что смог помочь. – Anonymous

1

Я предложил бы использовать String#replace путем подачи функции:

var text = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}'; 

var result = text.replace(/{{.*?}}/g, function (match) { 
    // *match* contains the full match, if you have captures 
    // then they will be handed in as additional arguments 
    return 'test'; 
}); 

На мой взгляд, это гораздо чище, чем возиться с индексами и такие. See this fiddle для рабочей версии.

+0

Я не знал, что 'replace' может использовать обратный вызов для второго параметра - это потрясающе, спасибо! – keldar

+0

Рад, что я мог бы помочь, по какой-то причине это не кажется широко известным. Я узнал об этом из «Секретной ниндзя JavaScript» Джона Ресига] (http://ejohn.org/blog/secrets-of-the-javascript-ninja-released/), это хорошо прочитано - хотя у него есть самурай на обложке, а не ниндзя :-) – mfeineis

+0

Ха - Я знаю книгу, но я не читал ее очень подробно! После вашего ответа здесь я сделаю это сейчас :). Учитывая, что он создал одну из самых известных библиотек JS! – keldar

Смежные вопросы