2017-01-21 5 views
0

Я работаю над движком шаблона, я пытаюсь поймать все строки внутри <%%>, но когда я работаю над шаблоном <% object.property%, все не удается. Моего код:RegExp не работает нормально

var render = function(input, data){ 
    var re = /<%([^%>]+)?%>/g; 
    var templateVarArray; 
    // var step = ""; 
    while((templateVarArray = re.exec(input))!=null){ 
     var strArray = templateVarArray[1].split("."); 
     // step+= templateVarArray[1]+" "; 
     if(strArray.length==1) 
      input = input.replace(templateVarArray[0], data[templateVarArray[1]]); 
     if(strArray.length==2){ 
      input = input.replace(templateVarArray[0], data[strArray[0]][strArray[1]]); 
     } 
    } 
    // return step; 
    return input; 
} 
var input = "<%test.child%><%more%><%name%><%age%>"; 

document.write(render(input,{ 
    test: { child: "abc"}, 
    more: "MORE", 
    name:"ivan", 
    age: 22 


})); 

Моего результат:

а <% больше%> <% имя%> 22

что я хочу: а MORE иван 22

Кроме того, ссылка RegExp/<% ([^%>] +)?%>/G указана в Интернете, я искал ее значение, но все еще не уверен, что я АНИНГ. Особенно зачем «+» и «?», Спасибо большое!

+1

Вы изменяете вход, но так как вы используете/г пометка ваш последний индекс не 0 - поэтому вы продолжаете поиск не с начала строки. Поэтому просто удалите/g. –

+0

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec –

ответ

1

Если добавить console.log() заявление он покажет, где следующий поиск будет иметь место:

while((templateVarArray = re.exec(input))!=null){ 
    console.log(re.lastIndex); // <-- insert this 
    var strArray = templateVarArray[1].split("."); 
    // step+= templateVarArray[1]+" "; 
    if(strArray.length==1) 
     input = input.replace(templateVarArray[0], data[templateVarArray[1]]); 
    if(strArray.length==2){ 
     input = input.replace(templateVarArray[0], data[strArray[0]][strArray[1]]); 
    } 
} 

Вы увидите что-то вроде:

14 
26 

Это означает, что при следующем запуске re.exec (...) он начнется с индексов 14 и 26 соответственно. Следовательно, вы пропустите некоторые из совпадений после того, как вы замените данные.

Как @Alexander указывает на «g» с конца регулярного выражения. Теперь вы увидите что-то вроде этого:

0 
0 

Это означает, что поиск будет начинаться каждый раз с начала строки, и теперь вы должны получить то, что вы искали:

abcMOREivan22

что касается ваших вопросов на RegEx и то, что он делает, давайте разберем куски друг от друга:

<% - this matches the literal '<' followed immediately by '%' 

([^%>]+) - the brackets (...) indicate we want to capture the portion of the string that matches the expression within the brackets 
    [^...] - indicates to match anything except what follows the '^'; without the '^' would match whatever pattern is within the [] 
    [^%>] - indicates to match and exclude a single character - either a '%' or '>' 
    [^%>]+ - '+' indicates to match one or more; in other words match one or more series of characters that is not a '%' and not a '>' 

? - this indicates we want to do reluctant matching (without it we do what is called 'greedy' matching) 

%> - this matches the literal '%' followed immediately by '>' 

Самая хитрая часть, чтобы понять это? " , Используемый в этом контексте означает, что мы прекращаем сопоставление с самым коротким шаблоном, который будет по-прежнему соответствовать общему регулярному выражению. В этом случае не имеет значения, включите ли вы его, хотя бывают моменты, когда это будет иметь значение в зависимости от совпадающих шаблонов.

Отдается Улучшение

Текущая логика ограничивается данными, гнездится два уровня вложенности. Для того, чтобы сделать это так, он может обрабатывать произвольное вложение вы могли бы сделать это:

Во-первых, добавить небольшую функцию, чтобы сделать замену:

var substitute = function (str, data) { 
    return str.split('.').reduce(function (res, item) { 
    return res[item]; 
    }, data); 
}; 

Затем измените время цикла, чтобы выглядеть следующим образом:

while ((templateVarArray = re.exec(input)) != null) { 
    input = input.replace(templateVarArray[0], substitute(templateVarArray[1], data)); 
    } 

Он не только обрабатывает любое количество уровней, вы можете найти другое применение для функции «substitute()».

+0

Спасибо, вы объясните это так подробно :) –

0

Документация RegExp.prototype.exec() говорит:

Если регулярное выражение использует «г» флаг, вы можете использовать метод Exec() несколько раз, чтобы найти последовательные матчи в одной и той же строке. Когда вы это сделаете, поиск начинается с подстроки str, заданной свойством lastIndex регулярного выражения (test() также увеличивает свойство lastIndex).

Но вы заменяете каждый матч в исходной строке, так следующий re.exec с lastIndex уже установлены не к нулю будет продолжать поиск не от начала и пропустите что-нибудь.

Так что, если вы хотите найти и заменить найдены результаты в исходной строке - просто опустить \gglobal key:

var render = function(input, data) { 
 
    var re = /<%([^%>]+)?%>/; 
 
    var templateVarArray; 
 
    // var step = ""; 
 
    while (!!(templateVarArray = re.exec(input))) { 
 
    var strArray = templateVarArray[1].split("."); 
 
    if (strArray.length == 1) 
 
     input = input.replace(templateVarArray[0], data[templateVarArray[1]]); 
 
    if (strArray.length == 2) { 
 
     input = input.replace(templateVarArray[0], data[strArray[0]][strArray[1]]); 
 
    } 
 
    } 
 
    // return step; 
 
    return input; 
 
} 
 
var input = "<%test.child%><%more%><%name%><%age%>"; 
 

 
document.write(render(input, { 
 
    test: { 
 
    child: "abc" 
 
    }, 
 
    more: "MORE", 
 
    name: "ivan", 
 
    age: 22 
 
}));

+0

Спасибо, Алекс, я понял это сейчас :) –

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