JavaScript: bir dizedeki son metin oluşumunu değiştirin


101

Aşağıdaki kod pasajıma bakın:

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

Bir kelimesinin son oluşumunu dizedeki bitiş kelimesiyle değiştirmek istiyorum, sahip olduğum şey işe yaramayacak çünkü değiştirme yöntemi yalnızca ilk geçtiği yerin yerini alacak. Bu pasajı yalnızca 'bir'in son örneğini değiştirecek şekilde nasıl değiştirebileceğimi bilen var mı?

Yanıtlar:


117

Peki, eğer dizi gerçekten kalıpla bitiyorsa, şunu yapabilirsiniz:

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

2
İyi bir fikir. Önce bu dizeden kaçılması gerekir (örnek verileriyle olmasa da), ki bu önemsiz değildir. :-(
TJ Crowder

@ Gerçek sorun yok! @TJ evet, gerçekten doğru: Ruth, normal ifadeler için kullanılan özel karakterleri içeren aradığınız "kelimeler" ile karşılaşırsanız, bunlardan "kaçmanız" gerekir, ki bu da TJ'nin dediği gibi biraz yanıltıcıdır (yine de imkansız değil).
Sivri

string1'in son oluşumunu string2 içinde değiştirmek isterseniz ne olur?
SuperUberDuper

1
@SuperUberDuper, "/" karakterleri ile çevrili bir şeyi eşleştirmek istiyorsanız iyi olur. RegExp örneği oluşturmanın iki yolu vardır: yapıcı ( new RegExp(string)) ve satır içi sözdizimi ( /something/). RegExp yapıcısını kullanırken "/" karakterlerine ihtiyacınız yoktur.
Sivri

3
@TechLife ` - things like + , * , ? ", Parantezler, köşeli parantezler ve belki başka şeyler ile tüm normal ifade meta karakterlerini" korumak "için dizeye bir dönüşüm uygulamanız gerekir .
Sivri

36

Sen kullanabilirsiniz String#lastIndexOfgeçen kelimenin geçtiği ve ardından bulmak için String#substringyedek dizesini oluşturmak ve birleştirme.

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

... veya bu satırlar boyunca.


1
Başka bir örnek: var nameSplit = item.name.lastIndexOf (","); eğer (adBölme! = -1) öğe.ismi = öğe.adı.substr (0, adBölümlü) + "ve" + öğe.adı.substr (adPlit + 2);
Ben Gotow

23

Bunun aptalca olduğunu biliyorum ama bu sabah kendimi yaratıcı hissediyorum:

'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"

Yani gerçekten yapmanız gereken tek şey bu işlevi String prototipine eklemek:

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

O halde şu şekilde çalıştırın: str = str.replaceLast('one', 'finish');

Bilmeniz gereken bir sınırlama, işlev boşlukla bölündüğünden, muhtemelen herhangi bir şeyi bir boşlukla bulamaz / değiştiremezsiniz.

Aslında, şimdi düşünüyorum da, boş bir jetonla bölerek 'boşluk' probleminin üstesinden gelebilirsiniz.

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

12
@Alexander Uhhh, lütfen bunu üretim kodunda kullanmayın ... Veya herhangi bir kod ... Basit bir normal ifade yeterli olacaktır.
hafif

12

Yukarıdaki normal ifadenin yanıtları kadar zarif değil, ancak aramızdaki kadar anlayışlı olmayanlar için takip etmesi daha kolay:

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

Bunun normal ifade örneklerinden muhtemelen daha yavaş ve daha savurgan olduğunun farkındayım, ancak dize manipülasyonlarının nasıl yapılabileceğinin bir örneği olarak yardımcı olabileceğini düşünüyorum. (Biraz da kısaltılabilir, ancak yine, her adımın net olmasını istedim.)


9

İşte yalnızca bölme ve birleştirme kullanan bir yöntem. Biraz daha okunabilir, bu yüzden paylaşmaya değer olduğunu düşündüm:

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

İyi çalışır, ancak dizge whathiç içermiyorsa dizenin başlangıcına değiştirme ekler . örneğin'foo'.replaceLast('bar'); // 'barfoo'
pie6k

8

Bu, Google aramamda ilk olarak ortaya çıktığı için burada cevap vereceğimi düşündüm ve değiştirilecek metin sonunda olmayabilirken, genel olarak bir karakter dizisinin son oluşumunun yerini alan bir yanıt yok (Matt'in yaratıcı cevabının dışında :)) dizenin.

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

Herhangi bir regex içermeyen basit bir cevap şöyle olacaktır:

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

2
Ya orijinal dizede bir oluşum yoksa?
tomazahlin

En çok kabul gören cevap benimkiyle aynı sonucu verir! İşte test sonucu:
Tim Long

Benimki:> s = s.substr (0, s.lastIndexOf ('d')) + 'bitiş' => 'bitiş' ... Bunların:> s = s.replace (yeni RegExp ('d' + '$ '),' finish ') =>' finish '
Tim Long

2

Dizeyi tersine çevirip, tersine çevrilmiş arama modelinin yalnızca ilk geçtiği yeri değiştiremez misiniz? Düşünüyorum . . .

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

Hız önemliyse, şunu kullanın:

/**
 * 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("");
}

RegExp kullanmaktan daha hızlıdır.


2

Basit bir çözüm, alt dize yöntemini kullanmak olacaktır. String, list element ile bittiği için, string.length kullanabilir ve lastIndexOfmetodu kullanmadan alt dizge için bitiş indeksini hesaplayabiliriz

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


1

Eski moda ve büyük kod ama mümkün olduğunca verimli:

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

Yukarıdaki cevapların hiçbirini beğenmedim ve aşağıdakileri buldum

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

Kullanım:

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

Umarım yardımcı olur!


0

Son değiştirilen npm paketini kullanmanızı öneririm .

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>

Bu, dize ve normal ifade değiştirmeleri için çalışır.


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

6
Normalde cevaba ek olarak bir açıklama
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.