JavaScript:替换字符串中最后出现的文本


97

请参阅下面的代码片段:

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

我想用字符串中的单词finish替换单词one的最后一次出现,我无法使用,因为replace方法将仅替换单词的首次出现。有谁知道我该如何修改该代码段,使其仅替换“ one”的最后一个实例

Answers:


115

好吧,如果字符串确实以模式结尾,则可以执行以下操作:

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

2
好主意。首先需要转义该字符串(尽管不附带她的示例数据),这是不平凡的。:-(
TJ人群

@露丝没有问题!@TJ是的,的确是这样:Ruth如果您要查找的“单词”包括正则表达式所用的特殊字符,则需要“转义”那些,正如TJ所说的那样,有些棘手(虽然不是不可能)。
Pointy

如果要替换string2中最后出现的string1怎么办?
SuperUberDuper 2015年

1
@SuperUberDuper很好,如果您要匹配用“ /”字符包围的内容。有两种创建RegExp实例的方法:构造函数(new RegExp(string))和内联语法(/something/)。使用RegExp构造函数时,不需要“ /”字符。
尖尖的2015年

3
@TechLife,您必须对字符串进行转换,以使用` - things like + , * , ?`,括号,方括号或其他方式来“保护”所有正则表达式元字符。
Pointy 2015年

35

您可以使用String#lastIndexOf查找单词的最后一次出现,然后通过String#substring并置来构建替换字符串。

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

...或沿着这些路线。


1
另一个示例:var nameSplit = item.name.lastIndexOf(“,”); 如果(nameSplit!= -1)item.name = item.name.substr(0,nameSplit)+“和” + item.name.substr(nameSplit + 2);
Ben Gotow

22

我知道这很愚蠢,但是今天早上我觉得很有创造力:

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

所以,实际上,您需要做的就是将此函数添加到String原型中:

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

然后像这样运行它: str = str.replaceLast('one', 'finish');

您应该知道的一个限制是,由于该函数是按空格分割的,因此您可能找不到/替换任何空格。

实际上,现在我想到了,您可以通过使用空令牌拆分来解决“空间”问题。

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,请不要在生产代码中使用此代码...或任何代码...一个简单的正则表达式就足够了。
轻微的

12

不像上面的正则表达式回答的那样优雅,但是对于我们当中不那么精明的人更容易遵循:

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

我意识到这可能比正则表达式示例更慢且更浪费,但我认为这可能有助于说明如何进行字符串操作。(也可以将其压缩一些,但是再次,我希望每一步都清楚。)


9

这是一种仅使用拆分和联接的方法。它更具可读性,因此值得分享:

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

它运作良好,但是如果string what根本不包含,它将在字符串的开头添加替换。例如'foo'.replaceLast('bar'); // 'barfoo'
pie6k

8

我以为我会在这里回答,因为这是我的Google搜索中的第一个问题,并且没有答案(Matt的创造性答案之外的问题是:)),当要替换的文本可能不在结尾时,一般不会替换最后一次出现的字符串的字符串。

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

4

没有任何正则表达式的简单答案是:

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

2
如果原始字符串中没有出现该怎么办?
tomazahlin

最被接受的答案返回与我相同的结果!测试结果如下:
Tim Long

我的:> s = s.substr(0,s.lastIndexOf('d'))+'finish'=>'finish'...他们的:> s = s.replace(new RegExp('d'+'$ “), '结束')=> '完成'
姆龙

2

您不能只反转字符串并仅替换首次出现的反转搜索模式吗?我在想 。。。

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

如果速度很重要,请使用以下命令:

/**
 * 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更快。


1

老式的大型代码,但尽可能高效:

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

简单的解决方案是使用子字符串方法。由于字符串以列表元素结尾,因此我们可以使用string.length并计算子字符串的结束索引,而无需使用lastIndexOf方法

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


1

我不喜欢以上任何答案,因此提出以下建议

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

用法:

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

希望有帮助!


0

我建议使用replace-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>

这适用于字符串和正则表达式替换。


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

6
通常,除了答案外,通常还需要一种解释
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.