Saya mencoba untuk (menggunakan Javascript) mengganti kemunculan pertama dari banyak substring dengan substring lain yang mungkin berisi campuran dari substring asli. Saya pikir mungkin paling sederhana untuk hanya menunjukkan contoh.

Contoh dari apa yang ingin saya lakukan

Misalkan saya punya peta

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

Dan sebuah paragraf

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

Setelah jendela dimuat, saya ingin mengubah ini menjadi

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

Upaya saya

Salah satu cara untuk hampir melakukan ini, adalah sebagai berikut:

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

Tapi ini mengembalikan I have a big dog, a huge mouse, another big dog, and another huge mouse. Ini tidak mengejutkan karena tag g memastikan bahwa semua kemunculan diganti, sedangkan saya hanya menginginkan kemunculan pertama.

Jadi upaya kedua saya adalah sebagai berikut:

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

Tapi ini mengembalikan I have a huge dog, a big mouse, and another dog, and another big cat. Itu karena dog telah diganti dengan big dog, dan kemudian big diganti dengan huge bukannya big sebelumnya cat.

Ringkasan

Bagaimana saya bisa mengganti kemunculan pertama dari beberapa substring dalam sebuah string secara non-iteratif? Ini sepertinya hal yang mungkin pernah ditanyakan sebelumnya di situs ini, tetapi saya belum dapat menemukannya di mana pun. Bantuan apa pun akan sangat dihargai, terima kasih!

0
Anthony 12 Mei 2021, 23:20

3 jawaban

Jawaban Terbaik

Mari kita bagi string menjadi dua bagian: sudah diproses (kiri) dan belum diproses (kanan). Pada setiap langkah, temukan salah satu string pencarian di bagian kanan dan ambil yang lebih dulu. Tambahkan irisan sebelum kata kunci dan penggantinya ke bagian kiri. Iris bagian kanan dari setelah pencarian. Ulangi sampai tidak ada string pencarian yang dapat ditemukan

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

Dan inilah solusi yang lebih sederhana dengan ekspresi reguler:

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

Atau, jika Anda menyukai kode "terkompresi",

let replace = (str, map, used = {}) => str.replace(
    new RegExp(Object.keys(map).join('|'), 'g'),
    m => used[m] ? m : map[used[m] = m])
0
georg 12 Mei 2021, 21:36

Anda dapat mencapai ini dengan loop for(... in ...) karena replace berfungsi secara default hanya untuk kecocokan pertama. Untuk tidak mengganti dua kali (fe big dari big dog), Anda dapat menggunakan dua var tambahan: satu untuk membuat string baru (newP) dan satu untuk mengganti kata (tempP ).

Setelah mengganti kata, Anda harus memperbarui string asli (paragraph) dengan menghapus bagian pertama termasuk kata. Ini dapat dilakukan misalnya dengan slice(). Setelah itu Anda hanya perlu menambahkan bagian yang dihapus ke string baru.

Setelah perulangan for, Anda cukup memasukkan string baru dan sisa string asli ke dalam paragraf dengan innerHTML.

Contoh kerja:

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>
0
biberman 12 Mei 2021, 22:57

Karena Anda hanya ingin mengganti kecocokan pertama, saya pikir cara terbaik adalah menyiapkan string dengan beberapa teks placeholder dan kemudian melakukan penggantian. Saya tidak suka ide menjalankan loop yang sama dua kali, tetapi tidak ada cara lain untuk menyiapkan string.

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>
0
Bülent Akgül 12 Mei 2021, 20:53