【问题标题】:Regex global replace not replacing first occurrence正则表达式全局替换不替换第一次出现
【发布时间】:2017-01-23 02:34:57
【问题描述】:

我正在尝试进行快速而肮脏的模板测试,但是当正则表达式替换时,它只替换最后一次出现,我认为\g 会替换所有副本。但它只匹配最后一次出现。

(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>

JsFiddle https://jsfiddle.net/ksu37c3b/

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

    如果相同的${..}(${Title}) 出现多次,/\$\{([^\}]+)\}(?![\S\s]*\$\{\1\})/g 将只匹配最后一个。要匹配所有元素,/\$\{([^\}]+)\}/g 将起作用,它不需要负前瞻(?![\S\s]*\$\{\1\})
    在字符串"${Title} - ${Name} - ${Title}"中,只有${Name}${Title}匹配模式,因为第一个和最后一个是一样的,如果你改变字符串,例如"${Title2} - ${Name} - ${Title}"会匹配所有元素,因为 ${Title2} 和 ${Title} 不相等。这就是(?![\S\s]*\$\{\1\}) 尝试做的事情,如果最后一个${..} 和当前${..} 相同,它将不匹配。

    更新

    那么,无论出现多少次,如何将每个标记替换为单个值。

    你可以使用match()方法获取一个发生的token数组,然后一个一个替换,下面的代码就可以了:

    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>​

    【讨论】:

    • 提示3次,而不是两次。
    • @Ryan The Leach 我更新了答案,上面的代码提示了2次。
    【解决方案2】:

    这应该做你想做的/\$\{([^\}]+)\}(?![\S\s]\$\{\1\})/

    我刚刚删除了否定前瞻中间的 *,因为它导致它每次都与最终出现的匹配。

    【讨论】:

    • 这样做的结果是“T - ${Name} - ${Title}”
    • 我一定是抄错了。去掉星号会产生 3 个提示,一个是标题,一个是名字,一个是标题。我要做的是有一个标题提示和一个名称提示。
    • 为什么不直接获取返回的内容,查看匹配结果的数组并检查是否有重复的内容?然后,您可以只提示尚未提示的匹配项。如果你在接下来的 3 小时内无法弄清楚,我会更深入地研究它,因为我在 3 小时内完成工作。
    • 我已经通过将值存储在一个对象中而不使用正则表达式来解决这个问题,我很好奇正则表达式是否能够进行多次替换。
    • 不太清楚您要达到的目标。我真的不知道你的意思。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多