JavaScript: thay thế lần xuất hiện cuối cùng của văn bản trong một chuỗi


97

Xem đoạn mã của tôi bên dưới:

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

Tôi muốn thay thế lần xuất hiện cuối cùng của từ một bằng từ kết thúc trong chuỗi, những gì tôi có sẽ không hoạt động vì phương thức thay thế sẽ chỉ thay thế lần xuất hiện đầu tiên của nó. Có ai biết cách tôi có thể sửa đổi đoạn mã đó để nó chỉ thay thế phiên bản cuối cùng của 'một'

Câu trả lời:


115

Chà, nếu chuỗi thực sự kết thúc bằng mẫu, bạn có thể làm như sau:

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

2
Ý tưởng tốt. Cần phải thoát khỏi chuỗi đó trước (mặc dù không phải với dữ liệu mẫu của cô ấy, được cấp), điều này không quan trọng. :-(
TJ Crowder

@Ruth không có prob! @TJ vâng, thực sự là đúng: Ruth nếu bạn kết thúc với "từ" bạn đang tìm kiếm bao gồm các ký tự đặc biệt được sử dụng cho cụm từ thông dụng, bạn cần phải "thoát" chúng, như TJ nói là một chút khó khăn (không phải là không thể mặc dù).
Pointy

Điều gì sẽ xảy ra nếu bạn muốn thay thế lần xuất hiện cuối cùng của string1 bên trong string2?
SuperUberDuper

1
@SuperUberDuper tốt nếu bạn muốn đối sánh thứ gì đó được bao quanh bởi các ký tự "/". Có hai cách để tạo một cá thể RegExp: hàm tạo ( new RegExp(string)) và cú pháp nội tuyến ( /something/). Bạn không cần các ký tự "/" khi bạn đang sử dụng hàm tạo RegExp.
Pointy

3
@TechLife, bạn sẽ phải áp dụng một phép chuyển đổi cho chuỗi để "bảo vệ" tất cả các siêu ký tự regex với ` - things like + , * , ? `, Dấu ngoặc đơn, dấu ngoặc vuông, có thể là những thứ khác.
Pointy

35

Bạn có thể sử dụng String#lastIndexOfđể tìm lần xuất hiện cuối cùng của từ, sau đó String#substringvà nối để tạo chuỗi thay thế.

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

... hoặc dọc theo những dòng đó.


1
Một ví dụ khác: var nameSplit = item.name.lastIndexOf (","); if (nameSplit! = -1) item.name = item.name.substr (0, nameSplit) + "và" + item.name.substr (nameSplit + 2);
Ben Gotow

22

Tôi biết điều này là ngớ ngẩn, nhưng tôi cảm thấy sáng tạo:

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

Vì vậy, tất cả những gì bạn cần làm là thêm chức năng này vào nguyên mẫu chuỗi:

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

Sau đó chạy nó như vậy: str = str.replaceLast('one', 'finish');

Một hạn chế mà bạn nên biết là, vì hàm được phân tách theo không gian, bạn có thể thể không thể tìm / thay thế bất kỳ thứ gì bằng khoảng trắng.

Trên thực tế, bây giờ tôi nghĩ về nó, bạn có thể giải quyết vấn đề 'không gian' bằng cách tách với một mã thông báo trống.

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, vui lòng không sử dụng mã này trong mã sản xuất ... Hoặc bất kỳ mã nào ... Một regex đơn giản là đủ.
nhẹ

12

Không thanh lịch như các câu trả lời regex ở trên, nhưng dễ theo dõi hơn đối với những người không hiểu biết trong chúng ta:

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

Tôi nhận thấy điều này có thể chậm hơn và lãng phí hơn so với các ví dụ regex, nhưng tôi nghĩ nó có thể hữu ích như một minh họa về cách các thao tác chuỗi có thể được thực hiện. (Nó cũng có thể được cô đọng một chút, nhưng một lần nữa, tôi muốn từng bước rõ ràng.)


9

Đây là một phương pháp chỉ sử dụng tách và nối. Nó dễ đọc hơn một chút nên nghĩ rằng nó đáng được chia sẻ:

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

Nó hoạt động tốt, tuy nhiên nó sẽ thêm thay thế vào đầu chuỗi nếu chuỗi không bao gồm whatchút nào. ví dụ'foo'.replaceLast('bar'); // 'barfoo'
pie6k

8

Tôi nghĩ tôi sẽ trả lời ở đây vì điều này xuất hiện đầu tiên trong tìm kiếm trên Google của tôi và không có câu trả lời nào (ngoài câu trả lời sáng tạo của Matt :)) nói chung thay thế lần xuất hiện cuối cùng của một chuỗi ký tự khi văn bản để thay thế có thể không ở cuối của chuỗi.

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

Một câu trả lời đơn giản mà không có bất kỳ regex nào sẽ là:

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

2
Điều gì sẽ xảy ra nếu không có sự xuất hiện trong chuỗi ban đầu?
tomazahlin

Câu trả lời được chấp nhận nhiều nhất trả về kết quả giống như của tôi! Đây là kết quả kiểm tra:
Tim Long

Của tôi:> s = s.substr (0, s.lastIndexOf ('d')) + 'finish' => 'finish' ... Của họ:> s = s.replace (new RegExp ('d' + '$ '),' finish ') =>' finish '
Tim Long

2

Bạn không thể chỉ đảo ngược chuỗi và chỉ thay thế lần xuất hiện đầu tiên của mẫu tìm kiếm đảo ngược? Tôi đang nghĩ . . .

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

Nếu tốc độ là quan trọng, hãy sử dụng:

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

Nó nhanh hơn so với sử dụng RegExp.


1

Mã cũ và lớn nhưng hiệu quả nhất có thể:

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

Giải pháp đơn giản sẽ là sử dụng phương pháp chuỗi con. Vì chuỗi kết thúc bằng phần tử danh sách, chúng ta có thể sử dụng string.length và tính toán chỉ số kết thúc cho chuỗi con mà không cần sử dụng lastIndexOfphương thức

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


1

Tôi không thích bất kỳ câu trả lời nào ở trên và đã đưa ra câu trả lời bên dưới

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

Sử dụng:

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

Hy vọng rằng sẽ giúp!


0

Tôi đề nghị sử dụng gói npm thay thế cuối cùng .

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>

Điều này hoạt động cho các thay thế chuỗi và regex.


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

6
Thông thường, một lời giải thích thường muốn thêm vào câu trả lời
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.