JavaScript: remplace la dernière occurrence de texte dans une chaîne

Voir mon extrait de code ci-dessous:

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

Je veux remplacer la dernière occurrence du mot one par le mot finish dans la chaîne, ce que j'ai ne fonctionnera pas car la méthode replace ne remplacera que la première occurrence de celui-ci. Est-ce que quelqu'un sait comment je peux modifier cet extrait de sorte qu'il ne remplace que la dernière instance de ' one '

57
demandé sur Cœur 2010-04-28 17:09:31

12 réponses

Eh bien, si la chaîne se termine vraiment par le motif, vous pouvez faire ceci:

str = str.replace(new RegExp(list[i] + '$'), 'finish');
76
répondu Pointy 2010-04-28 13:12:08

Vous pouvez utiliser String#lastIndexOf pour trouver la dernière occurrence du mot, puis String#substring et la concaténation de construire la chaîne de remplacement.

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

...ou le long de ces lignes.

31
répondu T.J. Crowder 2010-04-28 13:12:23

Je sais que c'est idiot, mais je me sens créatif ce matin:

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

Donc, vraiment, tout ce que vous devez faire est d'ajouter cette fonction au prototype de chaîne:

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

Ensuite, exécutez-le comme suit: str = str.replaceLast('one', 'finish');

une limitation que vous devriez savoir est que, puisque la fonction est divisée par espace, vous probablement ne pouvez pas trouver / remplacer quoi que ce soit par un espace.

En fait, maintenant que j'y pense, vous pourriez contourner le problème de l'espace en divisant avec un vide jeton.

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');
16
répondu Matt 2010-04-28 13:57:41

Pas aussi élégant que les réponses regex ci-dessus, mais plus facile à suivre pour les moins avertis parmi nous:

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

Je me rends compte que c'est probablement plus lent et plus inutile que les exemples regex, mais je pense que cela pourrait être utile comme illustration de la façon dont les manipulations de chaînes peuvent être effectuées. (Il peut aussi être condensé un peu, mais encore une fois, je voulais que chaque étape soit claire.)

10
répondu WilsonCPU 2011-05-27 11:46:17

Pensé que je répondrais ici puisque cela est apparu en premier dans ma recherche Google et il n'y a pas de réponse (en dehors de la réponse créative de Matt :)) qui remplace génériquement la dernière occurrence d'une chaîne de caractères lorsque le texte à remplacer peut ne pas être à la fin de la chaîne.

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(',', ';'));
8
répondu Irving 2013-08-09 20:51:24

Voici une méthode qui utilise uniquement le fractionnement et la jointure. C'est un peu plus lisible, alors j'ai pensé que ça valait la peine d'être partagé:

    String.prototype.replaceLast = function (what, replacement) {
        var pcs = this.split(what);
        var lastPc = pcs.pop();
        return pcs.join(what) + replacement + lastPc;
    };
4
répondu mr.freeze 2016-01-05 23:00:04

Ne pourriez-vous pas simplement inverser la chaîne et remplacer uniquement la première occurrence du motif de recherche inversé? Je suis en train de penser . . .

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
répondu user819644 2014-09-17 13:50:19

À l'Ancienne et code mais efficace que possible:

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
répondu dario nascimento 2014-01-05 16:23:22

Si la vitesse est importante, utilisez ceci:

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

C'est plus rapide que D'utiliser RegExp.

1
répondu Pascut 2017-02-23 15:55:47

Je suggère d'utiliser le paquetreplace-last npm.

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>

Cela fonctionne pour les remplacements de chaînes et de regex.

0
répondu danday74 2018-03-19 20:32:45

, Une réponse simple, sans regex serait:

str = str.substr(0, str.lastIndexOf(list[i])) + 'finish'
0
répondu Tim Long 2018-08-16 09:33:39
str = (str + '?').replace(list[i] + '?', 'finish');
-1
répondu zaxvox 2015-02-13 01:02:09