Esiste un metodo di giunzione per le stringhe?


87

Javascript splicefunziona solo con gli array. Esiste un metodo simile per le stringhe? O devo creare la mia funzione personalizzata?

I metodi substr(), e substring()restituiranno solo la stringa estratta e non modificheranno la stringa originale. Quello che voglio fare è rimuovere una parte dalla mia stringa e applicare la modifica alla stringa originale. Inoltre, il metodo replace()non funzionerà nel mio caso perché desidero rimuovere parti che iniziano da un indice e finiscono in un altro indice, esattamente come posso fare con il splice()metodo. Ho provato a convertire la mia stringa in un array, ma questo non è un metodo accurato.


str.splitpotrebbe essere la funzione che stai cercando: google.com/#q=javascript+string+split
Anderson Green

1
Cosa c'è che non va str = str.slice()?
elclanrs

1
Sembra un problema XY, cosa stai cercando di fare esattamente? Le stringhe non vengono passate per riferimento, a differenza degli array e degli oggetti, quindi non si mutano le stringhe, ne si creano di nuove o si riassegna la nuova a quella vecchia.
elclanrs


6
return string.slice(0, startToSplice) + string.slice(endToSplice);, no?
raina77ow

Risposte:


88

È più veloce tagliare la stringa due volte, in questo modo:

function spliceSlice(str, index, count, add) {
  // We cannot pass negative indexes directly to the 2nd slicing operation.
  if (index < 0) {
    index = str.length + index;
    if (index < 0) {
      index = 0;
    }
  }

  return str.slice(0, index) + (add || "") + str.slice(index + count);
}

rispetto all'utilizzo di una divisione seguita da un join (metodo di Kumar Harsh), in questo modo:

function spliceSplit(str, index, count, add) {
  var ar = str.split('');
  ar.splice(index, count, add);
  return ar.join('');
}

Ecco un jsperf che confronta i due e un paio di altri metodi. (jsperf è inattivo da alcuni mesi. Si prega di suggerire alternative nei commenti.)

Sebbene il codice sopra implementi funzioni che riproducono la funzionalità generale di splice, l'ottimizzazione del codice per il caso presentato dal richiedente (ovvero, non aggiungendo nulla alla stringa modificata) non modifica le prestazioni relative dei vari metodi.


3
Puoi aggiungerlo a livello globale con: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Tieni presente che non funziona esattamente allo stesso modo del metodo di splice dell'array perché le stringhe sono immutabili (non puoi modificarle una volta create). Quindi l'utilizzo sarebbe come:var s="ss"; s = s.splice(0,1,"t");
William Neely

@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};sarebbe standard per la manipolazione delle stringhe poiché hai detto che è immutabile.
Mr. Polywhirl

spliceSlice e spliceSplit non sono funzionalmente uguali perché Array.prototype.splice accetta indici negativi: jsfiddle.net/sykteho6/5 .
Martijn

1
@Mzialla Grazie, ho aggiunto del codice per occuparmene.
Louis

Creazione di variabili temporanee e introduzione di posizioni per errori off-by-one, per non parlare del codice che richiede più tempo per l'elaborazione da parte degli umani rispetto a split (""). Splice (...). Join ("") è un compromesso merita considerazione. Il problema della velocità è solo un problema se è un problema.
Ben Fletcher

15

modificare

Questo ovviamente non è il modo migliore per "unire" una stringa, l'avevo fornito come esempio di come sarebbe stata l'implementazione, il che è difettoso e molto evidente da split (), splice () e join (). Per un'implementazione molto migliore, vedere il metodo di Louis .


No, non esiste una cosa come a String.splice, ma puoi provare questo:

newStr = str.split(''); // or newStr = [...str];
newStr.splice(2,5);
newStr = newStr.join('');

Mi rendo conto che non esiste una splicefunzione come in Arrays, quindi devi convertire la stringa in un array. Sfortuna ...


nel mio caso sto lavorando su una stringa dinamica quindi ho bisogno di specificare gli indici e non il valore del carattere.
ProllyGeek

Sì, purtroppo è corretto. Ma puoi ottenere l'indice di un carattere usando String.prototype.indexOf as"asdsd".indexOf('s');
kumarharsh

3
Invece di usare str.split, puoi usare la sintassi di diffusione ES6 in questo modo:[...str]
robbie

5

Ecco un bel curry che offre una migliore leggibilità (IMHO):

La firma della seconda funzione è identica al Array.prototype.splicemetodo.

function mutate(s) {
    return function splice() {
        var a = s.split('');
        Array.prototype.splice.apply(a, arguments);
        return a.join('');
    };
}

mutate('101')(1, 1, '1');

So che c'è già una risposta accettata, ma spero che sia utile.


1
Np. Puoi anche astrarlo per consentire, ad esempio, un 'method'parametro opzionale in modo da poter passare in un Array.prototype[method]e trattare le stringhe completamente come array. Inoltre, con questo solo uno, si potrebbe astratto l'effettivo processo ad un'altra funzione - e se c'è alcuna stringa, restituire una funzione che avrà la stringa e invertire il curry: mutate()(1, 1, '1')('101'); Potresti anche duckType gli argomenti per liberare il curry dall'invocazione vuota, persino incapsulare un metodo, se stesso. Se hai bisogno di questa roba, potresti voler esaminare il modello di comando . Sputa solo palle qui.
Cody

3

Vorrei offrire un'alternativa più semplice ai metodi Kumar / Cody e Louis. In tutti i test che ho eseguito, si comporta alla stessa velocità del metodo Louis (vedi i test del violino per i benchmark).

String.prototype.splice = function(startIndex,length,insertString){
    return this.substring(0,startIndex) + insertString + this.substring(startIndex + length);
};

Puoi usarlo in questo modo:

var creditCardNumber = "5500000000000004";
var cardSuffix = creditCardNumber.splice(0,12,'****');
console.log(cardSuffix);  // output: ****0004

Vedi i risultati del test: https://jsfiddle.net/0quz9q9m/5/


dovresti almeno fare `+ (insertString ||" ") +` invece di `+ insertString + , otherwise the third argument is not optional. This implementation also doesn't take care of startIndex <0` a differenza di altri suggerimenti. Ottimo esempio di utilizzo, però
YakovL

3

Sembra esserci molta confusione che è stata affrontata solo nei commenti di elclanrs e raina77ow, quindi lasciatemi pubblicare una risposta chiarificatrice.

Una precisazione

Da " string.splice" ci si può aspettare che, come quello per gli array:

  • accetta fino a 3 argomenti: posizione iniziale, lunghezza e (facoltativamente) inserimento (stringa)
  • restituisce la parte tagliata
  • modifica la stringa originale

Il problema è che il requisito 3d non può essere soddisfatto perché le stringhe sono immutabili (correlati: 1 , 2 ), ho trovato il commento più dedicato qui :

In JavaScript le stringhe sono tipi di valore primitivi e non oggetti ( spec ). In realtà, come di ES5, sono uno dei soli 5 tipi di valore a fianco null, undefined, numbere boolean. Le stringhe vengono assegnate per valore e non per riferimento e vengono passate come tali. Pertanto, le stringhe non sono solo immutabili, sono un valore . Cambiare la stringa "hello"in be "world"è come decidere che d'ora in poi il numero 3 è il numero 4 ... non ha senso.

Quindi, tenendo conto di questo, ci si può aspettare che la string.splicecosa " " solo:

  • accetta fino a 2 argomenti: posizione iniziale, lunghezza (l'inserimento non ha senso poiché la stringa non viene modificata)
  • restituisce la parte tagliata

che è ciò che substrfa; o, in alternativa,

  • accetta fino a 3 argomenti: posizione iniziale, lunghezza e (facoltativamente) inserimento (stringa)
  • restituisce la stringa modificata (senza la parte tagliata e con inserimento)

che è l'argomento della prossima sezione.

Soluzioni

Se ti interessa l'ottimizzazione, dovresti probabilmente utilizzare l'implementazione di Mike:

String.prototype.splice = function(index, count, add) {
    if (index < 0) {
        index += this.length;
        if (index < 0)
            index = 0;
    }
    return this.slice(0, index) + (add || "") + this.slice(index + count);
}

Tuttavia, il trattamento dell'indice di fuori limite può variare. A seconda delle tue esigenze, potresti volere:

    if (index < 0) {
        index += this.length;
        if (index < 0)
            index = 0;
    }
    if (index >= this.length) {
        index -= this.length;
        if (index >= this.length)
            index = this.length - 1;
    }

o anche

    index = index % this.length;
    if (index < 0)
        index = this.length + index;

Se non ti interessa le prestazioni, potresti adattare il suggerimento di Kumar che è più diretto:

String.prototype.splice = function(index, count, add) {
    var chars = this.split('');
    chars.splice(index, count, add);
    return chars.join('');
}

Prestazione

La differenza di prestazioni aumenta drasticamente con la lunghezza della corda. jsperf mostra che per stringhe con la lunghezza di 10 l'ultima soluzione (divisione e unione) è due volte più lenta della prima soluzione (usando slice), per stringhe di 100 lettere è x5 e per stringhe di 1000 lettere è x50, in Ops / sec è:

                      10 letters   100 letters   1000 letters
slice implementation    1.25 M       2.00 M         1.91 M
split implementation    0.63 M       0.22 M         0.04 M

nota che ho cambiato gli argomenti 1 ° e 2d quando sono passato da 10 lettere a 100 lettere (sono comunque sorpreso che il test per 100 lettere sia più veloce di quello per 10 lettere).


2

Usa semplicemente substr per string

ex.

var str = "Hello world!";
var res = str.substr(1, str.length);

Risultato = ello world!


1

Quindi, qualunque sia l'aggiunta del metodo di giunzione a un prototipo di stringa non può funzionare in modo trasparente alle specifiche ...

Facciamolo estendere:

String.prototype.splice = function(...a){
    for(var r = '', p = 0, i = 1; i < a.length; i+=3)
        r+= this.slice(p, p=a[i-1]) + (a[i+1]||'') + this.slice(p+a[i], p=a[i+2]||this.length);
    return r;
}
  • Ogni 3 argomenti raggruppa "inserimenti" in stile giunzione.
  • Speciale se c'è più di un gruppo di 3 argomenti, la fine di ogni taglio sarà l'inizio del successivo.
    • "0123456789" .plice (4,1, "quarto", 8,1, "ottavo"); // return "0123fourth567eighth9"
  • Puoi eliminare o azzerare l'ultimo argomento in ogni gruppo (quello trattato come "niente da inserire")
    • "0123456789" .plice (-4,2); // return "0123459"
  • Puoi eliminare tutto tranne il primo argomento nell'ultimo gruppo (quello trattato come "taglia tutto dopo la prima posizione dell'argomento")
    • "0123456789" .plice (0,2, null, 3,1, null, 5,2, "/", 8); // return '24 / 7 '
  • se passi più volte, DEVI controllare da solo l'ordinamento delle posizioni da sinistra a destra!
  • E se non vuoi, NON DEVI usarlo in questo modo:
    • '0123456789'.splice (4, -3,' cosa? '); // return "0123 what? 123456789"

0

La risposta del metodo Louis , come Stringfunzione prototipo:

String.prototype.splice = function(index, count, add) {
  if (index < 0) {
    index = this.length + index;
    if (index < 0) {
      index = 0;
    }
  }
  return this.slice(0, index) + (add || "") + this.slice(index + count);
}

Esempio:

 > "Held!".splice(3,0,"lo Worl")
 < "Hello World!"

0

Il metodo spliceSlice di Louis fallisce quando il valore aggiunto è 0 o altri valori falsi, ecco una soluzione:

function spliceSlice(str, index, count, add) {
  if (index < 0) {
    index = str.length + index;
    if (index < 0) {
      index = 0;
    }
  }
  const hasAdd = typeof add !== 'undefined';
  return str.slice(0, index) + (hasAdd ? add : '') + str.slice(index + count);
}

0

Ho risolto il mio problema usando questo codice, è in qualche modo un sostituto per la giunzione mancante.

let str = "I need to remove a character from this";
let pos = str.indexOf("character")

if(pos>-1){
  let result = str.slice(0, pos-2) + str.slice(pos, str.length);
  console.log(result) //I need to remove character from this 
}

Avevo bisogno di rimuovere un carattere prima / dopo una certa parola, dopo aver ottenuto la posizione la stringa viene divisa in due e quindi ricomposta rimuovendo in modo flessibile i caratteri usando un offset lungo pos

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.