簡體   English   中英

替換 Javascript 中第一次出現的許多子字符串

[英]Replacing first occurrence of many substrings in Javascript

我正在嘗試(使用 Javascript)將許多子字符串的第一次出現替換為其他可能包含原始子字符串混合的子字符串。 我認為僅顯示一個示例可能是最簡單的。

我想做的一個例子

假設我有一個 map

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>

加載 window 后,我想將其更改為

<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而不是之前的big cat

概括

如何非迭代地替換字符串中多個子字符串的第一次出現? 這似乎是以前在這個網站上可能被問過的那種事情,但我無法在任何地方找到它。 任何幫助將不勝感激,謝謝!

由於您只想替換第一個匹配項,我認為最好的方法是使用一些占位符文本准備字符串,然后進行替換。 我不喜歡兩次運行相同循環的想法,但是沒有其他方法可以准備字符串。

 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>

讓我們將字符串分成兩部分:已處理(左)和尚未處理(右)。 在每一步中,在右側找到一個搜索字符串,然后取第一個。 在關鍵字之前添加切片並將替換添加到左側部分。 從搜索后切出正確的部分。 重復直到找不到搜索字符串

 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])

您可以使用for(... in...)循環來實現這一點,因為 replace 默認情況下僅適用於第一個匹配項。 為了不替換兩次(從big dog到 fe big ),您可以使用兩個輔助變量:一個用於構建新字符串( newP ),另一個用於替換單詞( tempP )。

替換單詞后,您必須通過刪除包含單詞的第一部分來更新原始字符串( paragraph )。 這可以通過例如slice()來完成。 之后,您只需將刪除的部分添加到新字符串中。

在 for 循環之后,您可以簡單地將新字符串和原始字符串的 rest 插入到帶有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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM