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

文字列内の単語oneの最後の出現を文字列内の単語finishで置き換えたいのですが、replaceメソッドは最初の出現のみを置き換えるため、使用できません。誰かがそのスニペットを修正して「1」の最後のインスタンスのみを置き換えるようにする方法を知っていますか

回答:


115

まあ、文字列が本当にパターンで終わっているなら、これを行うことができます:

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

2
良いアイデア。最初にその文字列をエスケープする必要があります(ただし、彼女のサンプルデータでは許可されていません)。これは重要です。:-(
TJクラウダー

@ルース問題ない!@TJはい、確かにそれは本当です:正規表現に使用される特殊文字を含む探している「単語」で終わる場合、ルースはそれらを「エスケープ」する必要があります。これはTJが言うように少しトリッキーです(ただし、不可能ではありません)。
先のとがった

string2内で最後に出現したstring1を置き換える場合はどうなりますか?
SuperUberDuper 2015年

1
@SuperUberDuperは、「/」文字で囲まれたものと一致させたい場合に適しています。RegExpインスタンスを作成するには、コンストラクター(new RegExp(string))とインライン構文(/something/)の2つの方法があります。RegExpコンストラクターを使用する場合、「/」文字は必要ありません。
ポインティ2015年

3
@TechLifeでは、文字列に変換を適用して、すべての正規表現メタ文字を` - things like + , * , ? `、かっこ、角かっこなどで「保護」する必要があります。
先のとがった

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( "、"); if(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');

知っておくべき制限の1つは、関数がスペースで分割されているため、おそらくスペースで何も検索/置換できないことです。

実際、今考えてみると、空のトークンで分割することで「スペース」の問題を回避できます。

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うーん、これを本番コードで使用しないでください...または任意のコード...単純な正規表現で十分です。
わずか

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

それはうまく機能しますが、文字列が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 2018

最も受け入れられた答えは私のものと同じ結果を返します!ここでは、テスト結果は次のとおりです。
ティム・ロング

鉱山:> s = s.substr(0、s.lastIndexOf( 'd'))+ 'finish' => 'finish' ...彼らのもの:> s = s.replace(new RegExp( 'd' + '$ ')、' finish ')=>' finish '
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を使用するよりも高速です。


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

簡単な解決策は、部分文字列メソッドを使用することです。文字列はリスト要素で終了しているため、lastIndexOfメソッドを使用せずにstring.lengthを使用して部分文字列の終了インデックスを計算できます

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>

これは文字列と正規表現の置換で機能します。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.