JavaScript: แทนที่ข้อความสุดท้ายในสตริง


102

ดูข้อมูลโค้ดของฉันด้านล่าง:

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

ฉันต้องการแทนที่คำที่เกิดขึ้นครั้งสุดท้ายด้วยคำว่าเสร็จสิ้นในสตริงสิ่งที่ฉันมีจะใช้ไม่ได้เพราะวิธีการแทนที่จะแทนที่การเกิดขึ้นครั้งแรกเท่านั้น มีใครรู้บ้างว่าฉันจะแก้ไขตัวอย่างข้อมูลนั้นเพื่อแทนที่อินสแตนซ์สุดท้ายของ 'one' ได้อย่างไร

คำตอบ:


119

ถ้าสตริงลงท้ายด้วยรูปแบบจริงๆคุณสามารถทำได้:

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

2
ความคิดที่ดี. ต้องหลีกเลี่ยงสตริงนั้นก่อน (แม้ว่าจะไม่ได้รับข้อมูลตัวอย่างก็ตาม) ซึ่งไม่สำคัญ :-(
TJ Crowder

@ รูทไม่มีพร็อบ! @TJ ใช่นั่นคือความจริง: รู ธ หากคุณลงท้ายด้วย "คำ" ที่คุณกำลังมองหาซึ่งรวมถึงอักขระพิเศษที่ใช้สำหรับนิพจน์ทั่วไปคุณจะต้อง "หลบหนี" ซึ่งตามที่ TJ กล่าวนั้นค่อนข้างยุ่งยากเล็กน้อย (ไม่เป็นไปไม่ได้เลย)
Pointy

จะเกิดอะไรขึ้นถ้าคุณต้องการแทนที่การเกิดครั้งสุดท้ายของ string1 ภายใน string2?
SuperUberDuper

1
@SuperUberDuper ดีถ้าคุณต้องการจับคู่สิ่งที่ล้อมรอบด้วยอักขระ "/" มีสองวิธีในการสร้างอินสแตนซ์ RegExp: ตัวสร้าง ( new RegExp(string)) และไวยากรณ์แบบอินไลน์ ( /something/) คุณไม่จำเป็นต้องใช้อักขระ "/" เมื่อคุณใช้ตัวสร้าง RegExp
Pointy

3
@TechLife คุณจะต้องใช้การเปลี่ยนแปลงกับสตริงเพื่อ "ปกป้อง" อักขระเมตาของ regex ทั้งหมดที่มี` - things like เครื่องหมาย + , * , ? `, วงเล็บ, วงเล็บเหลี่ยม, หรืออย่างอื่นก็ได้
Pointy

37

คุณสามารถใช้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

23

ฉันรู้ว่ามันโง่ แต่เช้านี้ฉันรู้สึกสร้างสรรค์:

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

ข้อ จำกัด อย่างหนึ่งที่คุณควรทราบก็คือเนื่องจากฟังก์ชันแบ่งตามช่องว่างคุณอาจไม่สามารถค้นหา / แทนที่อะไรด้วยช่องว่างได้

ที่จริงตอนนี้ฉันคิดแล้วคุณสามารถแก้ไขปัญหา 'space' ได้โดยการแยกโทเค็นเปล่า

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

13
@ อเล็กซานเดอร์เอ่อโปรดอย่าใช้สิ่งนี้ในรหัสการผลิต ... หรือรหัสใด ๆ ... regex ง่ายๆก็เพียงพอแล้ว
เล็กน้อย

12

ไม่สวยหรูเหมือนคำตอบของ regex ข้างต้น แต่ง่ายต่อการติดตามสำหรับคนที่ไม่เข้าใจในหมู่พวกเรา:

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

ฉันตระหนักดีว่าสิ่งนี้น่าจะช้ากว่าและสิ้นเปลืองกว่าตัวอย่าง regex แต่ฉันคิดว่ามันอาจมีประโยชน์ในการเป็นภาพประกอบว่าสามารถปรับแต่งสตริงได้อย่างไร (สามารถย่อได้เล็กน้อย แต่อีกครั้งฉันต้องการให้แต่ละขั้นตอนชัดเจน)


9

นี่เป็นวิธีที่ใช้เฉพาะการแยกและการรวม อ่านได้ง่ายขึ้นเล็กน้อยดังนั้นจึงคิดว่าควรค่าแก่การแบ่งปัน:

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

ทำงานได้ดีอย่างไรก็ตามจะเพิ่มการแทนที่เพื่อเริ่มต้นสตริงหากสตริงไม่รวมwhatเลย เช่น'foo'.replaceLast('bar'); // 'barfoo'
Adam Pietrasiak

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

5

คำตอบง่ายๆที่ไม่มี regex คือ:

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

2
จะเกิดอะไรขึ้นถ้าไม่มีการเกิดขึ้นในสตริงเดิม?
tomazahlin

คำตอบที่ได้รับการยอมรับมากที่สุดให้ผลลัพธ์เหมือนกับของฉัน! นี่คือผลการทดสอบ:
Tim Long

ของฉัน:> s = s.substr (0, s.lastIndexOf ('d')) + 'finish' => 'finish' ... Theirs:> s = s.replace (RegExp ใหม่ ('d' + '$ '),' เสร็จสิ้น ') =>' เสร็จสิ้น '
Tim Long

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


2

วิธีแก้ปัญหาง่ายๆคือใช้วิธีการสตริงย่อย เนื่องจากสตริงลงท้ายด้วยองค์ประกอบรายการเราสามารถใช้ string.length และคำนวณดัชนีสิ้นสุดสำหรับสตริงย่อยได้โดยไม่ต้องใช้lastIndexOfวิธีการ

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


1

ฉันไม่ชอบคำตอบใด ๆ ข้างต้นและมาพร้อมกับด้านล่าง

function isString(variable) { 
    return typeof (variable) === 'string'; 
}

function replaceLastOccurenceInString(input, find, replaceWith) {
    if (!isString(input) || !isString(find) || !isString(replaceWith)) {
        // 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

รหัสเก่าและใหญ่ แต่มีประสิทธิภาพที่สุด:

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

0

ฉันขอแนะนำให้ใช้แพ็คเกจแทนที่ล่าสุด 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
โดยทั่วไปต้องการคำอธิบายเพิ่มเติมจากคำตอบ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.