it-swarm.com.de

JavaScript: Ersetzt das letzte Vorkommen von Text in einer Zeichenfolge

Sehen Sie mein Code-Snippet unten:

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

Ich möchte das letzte Vorkommen des Word-Elements durch das Word-Finish in der Zeichenfolge ersetzen. Was ich habe, funktioniert nicht, da die Replace-Methode nur das erste Vorkommen davon ersetzt. Weiß jemand, wie ich dieses Snippet so anpassen kann, dass es nur die letzte Instanz von 'Eins' ersetzt?

63
Ruth

Wenn die Zeichenfolge wirklich mit dem Muster endet, können Sie Folgendes tun:

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

Sie können String#lastIndexOf verwenden, um das letzte Vorkommen des Words zu ermitteln, und dann String#substring und Verkettung, um die Ersatzzeichenfolge zu erstellen.

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

... oder in diese Richtung.

34
T.J. Crowder

Ich weiß, dass das dumm ist, aber ich fühle mich heute Morgen kreativ:

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

Sie müssen also lediglich diese Funktion zum String-Prototyp hinzufügen:

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

Dann führe es so aus: str = str.replaceLast('one', 'finish');

Eine Einschränkung, die Sie kennen sollten, ist die Tatsache, dass wahrscheinlich nichts mit einem Leerzeichen finden/ersetzen kann, da die Funktion nach Leerzeichen aufgeteilt wird.

Jetzt, wo ich darüber nachdenke, könnte man das "Leerzeichen" -Problem umgehen, indem man sich mit einem leeren Token teilt.

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
Matt

Nicht so elegant wie die Regex-Antworten oben, aber für Nicht-Begabte unter uns leichter zu folgen:

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

Ich weiß, dass dies wahrscheinlich langsamer und verschwenderischer ist als die Beispiele für reguläre Ausdrücke, aber ich denke, es könnte hilfreich sein, um zu veranschaulichen, wie String-Manipulationen durchgeführt werden können. (Es kann auch etwas verdichtet werden, aber ich wollte, dass jeder Schritt klar ist.) 

10
WilsonCPU

Ich dachte, ich würde hier antworten, da dies in meiner Google-Suche zuerst aufkam und es keine Antwort gibt (außerhalb von Matts kreativer Antwort :)), die generisch das letzte Vorkommen einer Zeichenfolge ersetzt, wenn der zu ersetzende Text nicht am Ende steht der Zeichenfolge.

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
Irving

Hier ist eine Methode, die nur das Teilen und Verbinden verwendet. Es ist ein bisschen lesbarer, also dachte ich, es lohnt sich zu teilen:

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

Eine einfache Antwort ohne Regex wäre:

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

Könnten Sie die Zeichenfolge nicht einfach umkehren und nur das erste Vorkommen des umgekehrten Suchmusters ersetzen? Ich denke . . .

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
Fusty

Wenn Geschwindigkeit wichtig ist, verwenden Sie Folgendes:

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

Es ist schneller als mit RegExp.

1
Pascut

Altmodischer und großer Code, jedoch so effizient wie möglich:

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

Eine einfache Lösung wäre die Verwendung der Teilstring-Methode. Da string mit dem Element list endet, können wir string.length verwenden und den Endindex für die Teilzeichenfolge berechnen, ohne die Methode lastIndexOf zu verwenden

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

1
Hexer338

Ich würde vorschlagen, das Paket replace-last npm zu verwenden.

var str = 'one two, one three, one four, one';
var result = replaceLast(str, 'one', 'finish');
console.log(result);
<script src="https://unpkg.com/[email protected]/replaceLast.js"></script>

Dies funktioniert für String- und Regex-Ersetzungen.

0
danday74

Ich mochte keine der obigen Antworten und fand die folgenden

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

Verwendungszweck:

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

Hoffentlich hilft das!

0
Pepijn Olivier