2017-01-23 2 views
0

Я пытаюсь сделать быстрый и грязный тест шаблона, но когда регулярное выражение заменяет, оно заменяет только последнее вхождение, я думал, что \g заменит все копии. но это соответствует только последнему вхождению.Regex global заменить не заменяет первое появление

(How to String.match() distinct it ${SOME_TEXT} using Regex)

То, что я пытаюсь сделать, это приглашение пользователю один раз для каждого уникального имени переменной.

Title = t 
name = n 
result = '${Title} - n - t' 

Использование /\$\{([^\}]+)\}/g работ, но побуждает МНОГОПОЛЬЗОВАТЕЛЬСКИЙ раз.

Title = t 
name = n 
Title = t 
result = 't - n - t' 

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

<html> 
<head> 
    <script type="application/javascript"> 

     window.copyToClipboard = function(n) { 
      var u = "_hiddenCopyText_", t, i, r; 
      t = document.getElementById(u); 
      t.textContent = n; 
      i = document.activeElement; 
      t.focus(); 
      t.setSelectionRange(0, t.value.length); 
      try { 
       r = document.execCommand("copy") 
      } catch (f) { 
       r = !1 
      } 
      return i && typeof i.focus == "function" && i.focus(), 
       t.textContent = "", 
       r 
     }; 
     //${varname} 
     window.templateRegex = /\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g; 
     window.test = " ${Title} - ${Name} - ${Title}" 
     window.copyTemplate = function (template) { 
      var result = template.replace(window.templateRegex, function(match, token){ 
       return window.prompt("replace value for ${"+token+"}","${"+token+"}"); 
      }); 
      window.copyToClipboard(result); 
     }; 

    </script> 
</head> 
<textarea id="_hiddenCopyText_"></textarea> 
<button onclick="copyTemplate(window.test)">Test</button> 
</html> 

JsFiddlehttps://jsfiddle.net/ksu37c3b/

ответ

1

Если такой же ${..} ($ {Title}) встречается несколько раз, /\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g будет соответствовать только последнему. Чтобы соответствовать всем элементам, /\$\{([^\}]+)\}/g будет работать, он не нуждается в отрицательном образе (?![\S\s]*\$\{\1\}).
В строке "${Title} - ${Name} - ${Title}" только ${Name} и ${Title} соответствуют шаблону, так как первый и последний совпадают, если вы меняете строку, например "${Title2} - ${Name} - ${Title}", она будет соответствовать всему элементу, потому что $ {Title2} и $ {Title} не равны. Это то, что делают (?![\S\s]*\$\{\1\}), если последние ${..} и текущий ${..} совпадают, это не будет соответствовать.

обновление

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

Вы можете использовать метод match(), чтобы получить массив лексем произошло, а затем заменить его один на один, следующий код будет работать:

window.templateRegex = /\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g; 
 
window.test = " ${Title} - ${Name} - ${Title}"; 
 
var userinput, reg, i; 
 
var arr = window.test.match(/\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g); 
 
for (i = 0; i < arr.length; i++) { 
 
    arr[i] = arr[i].replace(/[\$\{\}]/g, ""); 
 
    userinput = window.prompt("replace value for " + arr[i]); 
 
    reg = new RegExp("\\$\\{" + arr[i] + "\\}", 'g'); 
 
    console.log(reg); 
 
    window.test = window.test.replace(reg, userinput); 
 
} 
 
alert(window.test);

Я изменил ваш код следующим образом:

window.copyToClipboard = function(n) { 
 
    var u = "_hiddenCopyText_", 
 
    t, i, r; 
 
    t = document.getElementById(u); 
 
    t.textContent = n; 
 
    //** snip **// 
 
}; 
 
//${varname} 
 
window.templateRegex = /\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g; 
 
window.test = " ${Title} - ${Name} - ${Title}"; 
 
window.copyTemplate = function(template) { 
 
    var result = template; 
 
    var userinput, reg; 
 
    var arr = result.match(/\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g); 
 
    for (let i = 0; i < arr.length; i++) { 
 
     arr[i] = arr[i].replace(/[\$\{\}]/g, ""); 
 
     userinput = window.prompt("replace value for " + arr[i]); 
 
     reg = new RegExp("\\$\\{" + arr[i] + "\\}", 'g'); 
 
     console.log(reg); 
 
     result = result.replace(reg, userinput); 
 
    } 
 
    window.copyToClipboard(result); 
 
};
<textarea id="_hiddenCopyText_"></textarea> 
 
<button onclick="copyTemplate(window.test)">Test</button>​

+0

Это подсказка 3 раза, а не дважды. –

+0

@ Ryan The Leach Я обновил свой ответ, код выше подсказок 2 раза. –

0

Это должно делать то, что вы хотите /\$\{([^\}]+)\}(?![\S\s]\$\{\1\})/

Я просто убрал * в середине отрицательного взгляда вперед, потому что это было причиной его соответствие окончательного вхождения каждого время.

+0

Выполнение этого результата «T - $ {Name} - $ {Title}" –

+0

Я, должно быть, скопировал его неправильно. Удаление звезды делает 3 подсказки, один для названия, один для имени, один для названия. То, что я пытаюсь сделать, - это одно приглашение для названия и одно приглашение для имени. –

+0

Почему бы вам просто не взять то, что было возвращено, посмотреть на массив согласованных результатов и проверить, было ли что-то дублировано? Затем вы можете просто запросить совпадения, которые уже не были запрошены. Если вы не можете понять это в ближайшие 3 часа, я углубится в него, так как я закончу работу через 3 часа. – Zei

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