2016-11-28 1 views
1

В настоящее время я пытаюсь создать небольшой механизм шаблонов в Javascript, заменив теги в теге html5 на поиск и замену регулярным выражением.Javascript exec maintaing state

Я использую exec на своем регулярном выражении, и я перебираю результаты. Мне интересно, почему регулярные выражения ломаются в своей текущей форме с флагом/g в регулярном выражении, но отлично ли это?

Проверьте сломанный пример и удалите флаг/g в регулярном выражении, чтобы просмотреть правильный вывод.

var TemplateEngine = function(tpl, data) { 
    var re = /(?:&lt;|<)%(.*?)(?:%&gt;|>)/g, match; 
    while(match = re.exec(tpl)) { 
    tpl = tpl.replace(match[0], data[match[1]]) 
    } 

    return tpl; 
} 

https://jsfiddle.net/stephanv/u5d9en7n/

Может кто-нибудь объяснить мне немного больше глубины, почему мой пример ломается именно на:

<p><%more%></p> 

ответ

1

Причина объясняется в javascript string exec strange behavior.

Решения вам нужно на самом деле String.replace с обратным вызовом в качестве замены:

var TemplateEngine = function(tpl, data) { 
    var re = /(?:&lt;|<)%(.*?)(?:%&gt;|>)/g, match; 
    return tpl.replace(re, function($0, $1) { 
    return data[$1] ? data[$1] : $0; 
    }); 
} 

См updated fiddle

Здесь регулярное выражение находит все неперекрывающиеся совпадения в строке, последовательно, и передает соответствие методу обратного вызова. $0 - полный матч, а $1 - содержание группы 1. Если data[$1] существует, он используется для замены целого совпадения, иначе весь матч вставляется обратно.

1

Проверить эту ссылку https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex. При использовании флага g объект, в котором вы сохраняете регулярное выражение в (re), будет отслеживать позицию последнего совпадения в свойстве lastIndex, а в следующий раз, когда вы используете этот объект, поиск начнется с позиции lastIndex.

Чтобы решить эту проблему можно либо вручную сбросить lastIndex свойству каждый раз или не сохранить регулярное выражение в объекте и использовать его в линию, как так:

while(match = /(?:&lt;|<)%(.*?)(?:%&gt;|>)/g.exec(tpl)) { 
Смежные вопросы