JavaScript: mengganti kemunculan teks terakhir dalam sebuah string


99

Lihat cuplikan kode saya di bawah ini:

var list = ['one', 'two', 'three', 'four'];
var str = 'one two, one three, one four, one';
for ( var i = 0; i < list.length; i++)
{
     if (str.endsWith(list[i])
     {
         str = str.replace(list[i], 'finish')
     }
 }

Saya ingin mengganti kemunculan terakhir dari kata satu dengan kata selesai dalam string, apa yang saya miliki tidak akan berfungsi karena metode ganti hanya akan menggantikan kemunculan pertama itu. Adakah yang tahu bagaimana saya bisa mengubah potongan itu sehingga hanya menggantikan contoh terakhir dari 'satu'

Jawaban:


115

Nah, jika string benar-benar diakhiri dengan pola, Anda bisa melakukan ini:

str = str.replace(new RegExp(list[i] + '$'), 'finish');

2
Ide bagus. Harus melarikan diri string itu terlebih dahulu (meskipun tidak dengan data sampelnya, diberikan), yang tidak sepele. :-(
TJ Crowder

@Ruth no prob! @TJ ya, memang itu benar: Ruth jika Anda berakhir dengan "kata-kata" yang Anda cari yang menyertakan karakter khusus yang digunakan untuk ekspresi reguler, Anda harus "melarikan diri", yang seperti yang dikatakan TJ sedikit rumit (bukan tidak mungkin).
Pointy

bagaimana jika Anda ingin mengganti kemunculan terakhir string1 di dalam string2?
SuperUberDuper

1
@SuperUberDuper baiklah jika Anda ingin mencocokkan sesuatu yang dikelilingi oleh karakter "/". Ada dua cara untuk membuat instance RegExp: konstruktor ( new RegExp(string)), dan sintaks sebaris ( /something/). Anda tidak memerlukan karakter "/" saat menggunakan konstruktor RegExp.
Pointy

3
@TechLife Anda harus menerapkan transformasi ke string untuk "melindungi" semua metakarakter regex dengan ` - things like + , * , ? `, Tanda kurung, tanda kurung siku, mungkin hal-hal lain.
Pointy

36

Anda bisa menggunakan String#lastIndexOfuntuk menemukan kemunculan terakhir dari kata tersebut, lalu String#substringdan penggabungan untuk membuat string pengganti.

n = str.lastIndexOf(list[i]);
if (n >= 0 && n + list[i].length >= str.length) {
    str = str.substring(0, n) + "finish";
}

... atau di sepanjang garis itu.


1
Contoh lain: var nameSplit = item.name.lastIndexOf (","); if (nameSplit! = -1) item.name = item.name.substr (0, nameSplit) + "dan" + item.name.substr (nameSplit + 2);
Ben Gotow

22

Saya tahu ini konyol, tetapi saya merasa kreatif pagi ini:

'one two, one three, one four, one'
.split(' ') // array: ["one", "two,", "one", "three,", "one", "four,", "one"]
.reverse() // array: ["one", "four,", "one", "three,", "one", "two,", "one"]
.join(' ') // string: "one four, one three, one two, one"
.replace(/one/, 'finish') // string: "finish four, one three, one two, one"
.split(' ') // array: ["finish", "four,", "one", "three,", "one", "two,", "one"]
.reverse() // array: ["one", "two,", "one", "three,", "one", "four,", "finish"]
.join(' '); // final string: "one two, one three, one four, finish"

Jadi sungguh, yang perlu Anda lakukan adalah menambahkan fungsi ini ke prototipe String:

String.prototype.replaceLast = function (what, replacement) {
    return this.split(' ').reverse().join(' ').replace(new RegExp(what), replacement).split(' ').reverse().join(' ');
};

Kemudian jalankan seperti ini: str = str.replaceLast('one', 'finish');

Salah satu batasan yang harus Anda ketahui adalah, karena fungsinya dipisahkan oleh spasi, Anda mungkin tidak dapat menemukan / mengganti apa pun dengan spasi.

Sebenarnya, sekarang setelah saya memikirkannya, Anda bisa mengatasi masalah 'ruang' dengan memisahkan dengan token kosong.

String.prototype.reverse = function () {
    return this.split('').reverse().join('');
};

String.prototype.replaceLast = function (what, replacement) {
    return this.reverse().replace(new RegExp(what.reverse()), replacement.reverse()).reverse();
};

str = str.replaceLast('one', 'finish');

11
@Alexander Uhhh, jangan gunakan ini dalam kode produksi ... Atau kode apa pun ... Regex sederhana sudah cukup.
Sedikit

12

Tidak seanggun jawaban regex di atas, tetapi lebih mudah diikuti bagi yang tidak terlalu paham di antara kita:

function removeLastInstance(badtext, str) {
    var charpos = str.lastIndexOf(badtext);
    if (charpos<0) return str;
    ptone = str.substring(0,charpos);
    pttwo = str.substring(charpos+(badtext.length));
    return (ptone+pttwo);
}

Saya menyadari ini kemungkinan lebih lambat dan lebih boros daripada contoh regex, tetapi saya pikir ini mungkin berguna sebagai ilustrasi tentang bagaimana manipulasi string dapat dilakukan. (Ini juga bisa sedikit diringkas, tetapi sekali lagi, saya ingin setiap langkah menjadi jelas.)


9

Berikut adalah metode yang hanya menggunakan pemisahan dan penggabungan. Ini sedikit lebih mudah dibaca jadi saya pikir itu layak untuk dibagikan:

    String.prototype.replaceLast = function (what, replacement) {
        var pcs = this.split(what);
        var lastPc = pcs.pop();
        return pcs.join(what) + replacement + lastPc;
    };

Ini bekerja dengan baik, namun itu akan menambahkan penggantian ke awal string jika string tidak disertakan whatsama sekali. misalnya'foo'.replaceLast('bar'); // 'barfoo'
pie6k

8

Pikir saya akan menjawab di sini karena ini muncul pertama kali dalam pencarian Google saya dan tidak ada jawaban (di luar jawaban kreatif Matt :)) yang secara umum menggantikan kemunculan terakhir dari serangkaian karakter ketika teks yang akan diganti mungkin tidak ada di bagian akhir dari string.

if (!String.prototype.replaceLast) {
    String.prototype.replaceLast = function(find, replace) {
        var index = this.lastIndexOf(find);

        if (index >= 0) {
            return this.substring(0, index) + replace + this.substring(index + find.length);
        }

        return this.toString();
    };
}

var str = 'one two, one three, one four, one';

// outputs: one two, one three, one four, finish
console.log(str.replaceLast('one', 'finish'));

// outputs: one two, one three, one four; one
console.log(str.replaceLast(',', ';'));

5

Jawaban sederhana tanpa regex adalah:

str = str.substr(0, str.lastIndexOf(list[i])) + 'finish'

2
Bagaimana jika tidak ada kemunculan dalam string aslinya?
tomazahlin

Jawaban yang paling diterima mengembalikan hasil yang sama dengan saya! Berikut adalah hasil tesnya:
Tim Long

Milik saya:> s = s.substr (0, s.lastIndexOf ('d')) + 'finish' => 'finish' ... Milik mereka:> s = s.replace (RegExp baru ('d' + '$ '),' finish ') =>' finish '
Tim Long

2

Tidak bisakah Anda membalikkan string dan hanya mengganti kemunculan pertama dari pola pencarian terbalik? Saya berpikir . . .

var list = ['one', 'two', 'three', 'four'];
var str = 'one two, one three, one four, one';
for ( var i = 0; i < list.length; i++)
{
     if (str.endsWith(list[i])
     {
         var reversedHaystack = str.split('').reverse().join('');
         var reversedNeedle = list[i].split('').reverse().join('');

         reversedHaystack = reversedHaystack.replace(reversedNeedle, 'hsinif');
         str = reversedHaystack.split('').reverse().join('');
     }
 }

2

Jika kecepatan itu penting, gunakan ini:

/**
 * Replace last occurrence of a string with another string
 * x - the initial string
 * y - string to replace
 * z - string that will replace
 */
function replaceLast(x, y, z){
    var a = x.split("");
    var length = y.length;
    if(x.lastIndexOf(y) != -1) {
        for(var i = x.lastIndexOf(y); i < x.lastIndexOf(y) + length; i++) {
            if(i == x.lastIndexOf(y)) {
                a[i] = z;
            }
            else {
                delete a[i];
            }
        }
    }

    return a.join("");
}

Ini lebih cepat daripada menggunakan RegExp.


2

Solusi sederhana akan menggunakan metode substring. Karena string diakhiri dengan elemen list, kita dapat menggunakan string.length dan menghitung indeks akhir untuk substring tanpa menggunakan lastIndexOfmetode

str = str.substring(0, str.length - list[i].length) + "finish"


1

Kode kuno dan besar tetapi seefisien mungkin:

function replaceLast(origin,text){
    textLenght = text.length;
    originLen = origin.length
    if(textLenght == 0)
        return origin;

    start = originLen-textLenght;
    if(start < 0){
        return origin;
    }
    if(start == 0){
        return "";
    }
    for(i = start; i >= 0; i--){
        k = 0;
        while(origin[i+k] == text[k]){
            k++
            if(k == textLenght)
                break;
        }
        if(k == textLenght)
            break;
    }
    //not founded
    if(k != textLenght)
        return origin;

    //founded and i starts on correct and i+k is the first char after
    end = origin.substring(i+k,originLen);
    if(i == 0)
        return end;
    else{
        start = origin.substring(0,i) 
        return (start + end);
    }
}

1

Saya tidak menyukai salah satu jawaban di atas dan muncul di bawah

function replaceLastOccurrenceInString(input, find, replaceWith) {
    if (!input || !find || !replaceWith || !input.length || !find.length || !replaceWith.length) {
        // returns input on invalid arguments
        return input;
    }

    const lastIndex = input.lastIndexOf(find);
    if (lastIndex < 0) {
        return input;
    }

    return input.substr(0, lastIndex) + replaceWith + input.substr(lastIndex + find.length);
}

Pemakaian:

const input = 'ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty';
const find = 'teen';
const replaceWith = 'teenhundred';

const output = replaceLastOccurrenceInString(input, find, replaceWith);
console.log(output);

// output: ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteenhundred twenty

Semoga membantu!


0

Saya akan menyarankan untuk menggunakan paket npm replace-last .

var str = 'one two, one three, one four, one';
var result = replaceLast(str, 'one', 'finish');
console.log(result);
<script src="https://unpkg.com/replace-last@latest/replaceLast.js"></script>

Ini berfungsi untuk penggantian string dan regex.


-1
str = (str + '?').replace(list[i] + '?', 'finish');

6
Biasanya, penjelasan umumnya diinginkan selain jawaban
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.