2010-04-28 16 views
47

Vedere il mio frammento di codice di seguito:JavaScript: sostituire ultima occorrenza di testo in una stringa

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

voglio sostituire l'ultima occorrenza della parola uno con la finitura di parola nella stringa, quello che ho non lo farò lavoro perché il metodo replace sostituirà solo la prima occorrenza di esso. Qualcuno sa come posso modificare tale frammento di modo che si sostituisce solo l'ultima istanza di 'uno'

risposta

67

Beh, se la stringa finisce davvero con il modello, si potrebbe fare questo:

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

Buona idea. Bisogna prima scappare da quella stringa (anche se non con i suoi dati di esempio, concessi), che non è banale. :-( –

+0

Grazie mille – Ruth

+0

@Ruth no prob! @TJ sì, in effetti è vero: Ruth se finisci con "parole" che stai cercando che includono i caratteri speciali usati per le espressioni regolari, avresti bisogno per "sfuggire" a quelli che, come dice TJ, è un po 'complicato (non impossibile però) – Pointy

30

Puoi utilizzare String#lastIndexOf per trovare l'ultima occorrenza della parola, quindi String#substring e la concatenazione per creare la stringa sostitutiva.

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

... o lungo quelle linee.

+0

Grazie mille – Ruth

+1

Un altro esempio: \t \t \t \t var nameSplit = item.name.lastIndexOf (","); \t \t \t \t se (nameSplit = -1!) \t \t \t \t \t item.name = item.name.substr (0, nameSplit) + "e" + item.name.substr (nameSplit + 2); –

16

So che questo è stupido, ma mi sento creativa di questa mattina:

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

Quindi, in realtà, tutto quello che avresti bisogno di fare è aggiungere questa funzione al prototipo String:

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

quindi eseguirlo in questo modo: str = str.replaceLast('one', 'finish');

una limitazione che si deve sapere è che, dal momento che la funzione è la divisione dallo spazio, è probabilmente non riesce a trovare/sostituire nulla con uno spazio.

In realtà, ora che ci penso, si potrebbe aggirare il problema dello "spazio" dividendo con un gettone vuoto.

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

Grazie mille – Ruth

+1

Lo chiami sciocco, lo chiamiamo utile! – Alexander

+7

@Alexander Uhhh, per favore non usare questo nel codice di produzione ... O qualsiasi codice ... Una semplice regex sarà sufficiente. – Slight

9

Non elegante come le risposte regex di cui sopra, ma più facile da seguire per la non-come-di buon senso in mezzo a noi:

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

Mi rendo conto che questo è probabile che più lento e più dispendioso rispetto agli esempi regex , ma penso che potrebbe essere utile come illustrazione di come si possano eseguire le stringhe di stringhe. (Può anche essere un po 'condensato, ma di nuovo, volevo che ogni passaggio fosse chiaro.)

5

Pensavo di rispondere qui poiché questo è venuto prima nella mia ricerca su Google e non c'è risposta (al di fuori della risposta creativa di Matt :)) che sostituisce genericamente l'ultima occorrenza di una stringa di caratteri quando il testo da sostituire potrebbe non essere alla fine della stringa.

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

codice vecchio stile e grande ma efficiente possibile:

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

Non potresti solo invertire la stringa e sostituire solo la prima occorrenza del modello di ricerca inversa? Sto pensando . . .

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(''); 
    } 
} 
-1
str = (str + '?').replace(list[i] + '?', 'finish'); 
+6

Normalmente, una spiegazione è generalmente richiesta oltre alla risposta –

3

Ecco un metodo che utilizza solo la scissione e la giunzione.E 'un po' più leggibile quindi pensano che sia vale la pena condividere:

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

Se la velocità è importante, utilizzare questo:

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

E 'più veloce rispetto all'utilizzo di RegExp.

Problemi correlati