替换 Javascript 中第一次出现的多个子字符串

时间:2021-05-12 20:20:23

标签: javascript html

我正在尝试(使用 Javascript)将 许多 子字符串的第一次 替换为可能包含原始字符串的混合的其他子字符串子串。我认为展示一个例子可能是最简单的。

我想做什么的例子

假设我有一张地图

const MAP = {
  "dog": "big dog",
  "big": "huge",
  "cat": "mouse"
}

和一个段落

<p id="paragraph">I have a dog, a big cat, another dog, and another big cat.</p>

加载窗口后,我想将其更改为

<p id="paragraph">I have a big dog, a huge mouse, another dog, and another big cat.</p>

我的尝试

几乎可以做到这一点的一种方法是:

var p = document.getElementById('paragraph');
window.onload = function() {
  var re = new RegExp(Object.keys(MAP).join("|"), "gi");
  p.innerHTML = p.innerHTML.replace(re, function(match) {return MAP[match];});
}

但这会返回 I have a big dog, a huge mouse, another big dog, and another huge mouse. 这并不奇怪,因为 g 标签确保所有出现的都被替换,而我只想要第一次出现。

那么我的第二次尝试如下:

var p = document.getElementById('paragraph');
var l = Object.keys(MAP);

window.onload = function() {
  for(var j=0; j<l.length; j++) {
    p.innerHTML = p.innerHTML.replace(l[j], MAP[l[j]]);
  }
}

但这会返回 I have a huge dog, a big mouse, and another dog, and another big cat. 那是因为 dog 已被 big dog 替换,然后 big 被替换为 huge 而不是 {{1 }} 在 big 之前。

总结

如何以非迭代方式替换字符串中第一次出现的多个子字符串?这似乎是本网站之前可能已经问过的那种事情,但我一直无法在任何地方找到它。任何帮助将不胜感激,谢谢!

3 个答案:

答案 0 :(得分:1)

由于您只想替换第一个匹配项,我认为最好的方法是用一些占位符文本准备字符串,然后进行替换。我不喜欢将同一个循环运行两次的想法,但没有其他方法可以准备字符串。

const MAP = {
  "dog": "big dog",
  "big": "huge",
  "cat": "mouse"
}

const p = document.querySelector("p");

let t = p.innerText;

Object.keys(MAP).forEach(x => {
 let parts = t.split(x);
 t = `${parts.shift()}%%${x.toUpperCase()}%%${parts.join(`${x}`)}`;
});

Object.keys(MAP).forEach(x => {
  t = t.replace(`%%${x.toUpperCase()}%%`, MAP[x]);
})

console.log(t)

p.innerText = t;

//<p id="paragraph">I have a big dog, a huge mouse, another dog, and another big cat.</p>
<p id="paragraph">I have a dog, a big cat, another dog, and another big cat.</p>

答案 1 :(得分:1)

让我们将字符串分成两部分:已处理(左)和尚未处理(右)。在每一步中,在右侧找到一个搜索字符串,并选择第一个。在关键字之前添加切片并将替换添加到左侧部分。搜索后切下右侧的部分。重复直到找不到搜索字符串

function replace(str, map) {
    let searches = new Set(Object.keys(map))
    let left = '', right = str

    while (1) {
        let pos = Infinity, search = ''

        for (let s of searches) {
            let i = right.indexOf(s)
            if (i >= 0 && i < pos) {
                pos = i;
                search = s;
            }
        }

        if (!search)
            break

        left += right.slice(0, pos) + map[search]
        right = right.slice(pos + search.length)

        searches.delete(search)
    }

    return left + right
}

//

const MAP = {
  "dog": "big dog",
  "big": "huge",
  "cat": "mouse"
}

text = "I have a dog, a big cat, another dog, and another big cat."

console.log(replace(text, MAP))

这里有一个更简单的正则表达式解决方案:

function replace(str, map) {
    let used = new Set,
        re = new RegExp(Object.keys(map).join('|'), 'g')
    return str.replace(re, m => {
        if (used.has(m))
            return m
        used.add(m)
        return map[m]
    })
}

//

const MAP = {
    "dog": "big dog",
    "big": "huge",
    "cat": "mouse"
}

text = "I have a dog, a big cat, another dog, and another big cat."

console.log(replace(text, MAP))

或者,如果您喜欢“压缩”代码,

let replace = (str, map, used = {}) => str.replace(
    new RegExp(Object.keys(map).join('|'), 'g'),
    m => used[m] ? m : map[used[m] = m])

答案 2 :(得分:1)

您可以使用 for(... in ...) 循环来实现这一点,因为默认情况下替换仅适用于第一场比赛。为了不替换两次(fe big from big dog),您可以使用两个辅助变量:一个用于构建新字符串(newP)和一个用于替换单词(tempP ).

替换单词后,您必须通过删除包括单词的第一部分来更新原始字符串 (paragraph)。例如,这可以通过 slice() 来完成。之后,您只需要将删除的部分添加到新字符串中。

在 for 循环之后,您可以简单地使用 innerHTML 将新字符串和原始字符串的其余部分插入到段落中。

工作示例

const MAP = {
  "dog": "big dog",
  "big": "huge",
  "cat": "mouse"
}
let newP = '';

window.addEventListener('DOMContentLoaded', function() {
  let paragraph = document.getElementById('paragraph').textContent;
  for(let key in MAP) {
    let tempP = paragraph.replace(key, MAP[key]);
    paragraph = tempP.slice(tempP.indexOf(MAP[key]) + MAP[key].length);
    newP += tempP.slice(0, tempP.indexOf(MAP[key]) + MAP[key].length);
  }
  document.getElementById('paragraph').innerHTML = newP + paragraph;
});
<p id="paragraph">I have a dog, a big cat, another dog, and another big cat.</p>