2015-05-02 10 views
5

Davvero, praticamente quello che dice il titolo.Limitare le volte che .split() si divide, piuttosto che troncare l'array risultante

Diciamo che avete questa stringa:

var theString = "a=b=c=d"; 

Ora, quando si esegue theString.split("=") il risultato è ["a", "b", "c", "d"] come previsto. E, naturalmente, quando si esegue theString.split("=", 2) si ottiene ["a", "b"], che dopo aver letto the MDN page for String#split() ha senso per me.

Tuttavia, il comportamento che sto cercando è più simile a Java di String#split(): Invece di costruire la matrice normalmente, per poi tornare i primi n elementi, si costruisce una serie di primo n-1 partite, poi aggiunge tutti i caratteri rimanenti come ultimo elemento dell'array. Vedere the relevant docs per una descrizione migliore.

Come posso ottenere questo effetto in Javascript?

Sto cercando la risposta con la migliore prestazione che funzioni come l'implementazione Java, anche se il modo in cui funziona può essere diverso.

Pubblicheremo il mio tentativo, ma non so come andare a scrivere questo a tutti.

risposta

6

Se si desidera che l'esatto equivalente della implementazione Java (senza controllo degli errori o clausole di guardia, ecc):

function split(str, sep, n) { 
    var out = []; 

    while(n--) out.push(str.slice(sep.lastIndex, sep.exec(str).index)); 

    out.push(str.slice(sep.lastIndex)); 
    return out; 
} 

console.log(split("a=b=c=d", /=/g, 2)); // ['a', 'b', 'c=d'] 

Questo ha il vantaggio di non calcolare la scissione completa in anticipo, come lei ha citato nella sua domanda .

+0

Potresti aggiungere una rapida spiegazione di come funziona? –

+0

@QPaysTaxes I iterate "limite" numero di volte e su ogni iterazione uso una espressione regolare per trovare la successiva occorrenza del carattere di suddivisione. La regex ricorda dove si trovava l'ultima partita e, una volta eseguita, so dove si trova la prossima partita. Aggiungo la sezione di stringa tra queste due posizioni su ogni iterazione. Fuori dal ciclo, aggiungo la sezione della stringa tra l'ultima corrispondenza regolare e la fine della stringa. –

+2

E poiché l'OP ha chiesto informazioni sulle prestazioni, questa implementazione è circa il doppio più veloce (in Chrome) degli altri due. Mi ha sorpreso! –

3

userei qualcosa di simile:

function JavaSplit(string,separator,n) { 
    var split = string.split(separator); 
    if (split.length <= n) 
     return split; 
    var out = split.slice(0,n-1); 
    out.push(split.slice(n-1).join(separator)); 
    return out; 
} 

Quello che stiamo facendo qui è:

  1. suddivisione della stringa interamente
  2. Prendendo i primi n-1 elementi, come descritto .
  3. Riunire gli elementi rimanenti.
  4. Aggiungendoli all'array dal passaggio 2 e ritorno.

Si potrebbe ragionevolmente pensare di poter concatenare tutte quelle chiamate insieme, ma lo .push() muta una matrice piuttosto che restituirne una nuova. È anche un po 'più facile per te seguire questa strada. più

+2

ciao, forse è necessario controllare la lunghezza dei risultati separata, è più grande di n prima di fare fetta, altrimenti solo restituire il risultato scissione. – Surely

+0

Buon punto; aggiunto. –

+0

Mi piace questo per la sua semplicità, ma accetto l'altro perché (per quanto posso dire senza benchmarking) è più efficiente. –

2

Una possibile implementazione:

function split(s, separator, limit) { 
    // split the initial string using limit 
    var arr = s.split(separator, limit); 
    // get the rest of the string... 
    var left = s.substring(arr.join(separator).length + separator.length); 
    // and append it to the array 
    arr.push(left); 
    return arr; 
} 

Fiddle è here.

+0

Anche se non sono abbastanza sicuro di 'length + 1' - immagino che dipenda dai tuoi requisiti - se vuoi avere un' separatore 'leader nell'ultimo elemento o meno. –

+0

Sostituisci '+ 1' con' + separator.length', nel caso in cui si ottenga un separatore multi-carattere. –

0

Stai cercando qualcosa di più vicino a PHP explode?

Qui è un metodo che ho ideato:

String.prototype.explode = function(sep, n) { 
    var arr = this.split(sep, n) 
    if (arr[n-1] != undefined) arr[n-1] += this.substring(arr.join(' ').length); 
    return arr; 
} 

Questo metodo divide la stringa del tipo normale, determina se abbiamo raggiunto il nostro limite, e utilizza substring aggiungere il testo oltre il nostro ultimo split (possiamo accedere direttamente l'offset del primo carattere oltre l'ultima spaccatura ottenendo il length di un join sulla matrice con un singolo carattere come separatore)

Questo metodo viene utilizzato come split:

012.
str = 'my/uri/needs/to/be/split'; 
splitResult = str.split('/', 4); 
explodeResult = str.explode('/', 4); 
console.log(splitResult); 
console.log(explodeResult); 

// The following will be written to the console: 
// splitResult: ["my", "uri", "needs", "to"] 
// explodeResult: ["my", "uri", "needs", "to/be/split"] 

E, naturalmente, questo può essere filata in funzione troppo:

function explode(str, sep, n) { 
    var arr = str.split(sep, n) 
    if (arr[n-1] != undefined) arr[n-1] += this.substring(arr.join(' ').length); 
    return arr; 
} 

str = 'my/uri/needs/to/be/split'; 
explodeResult = explode(str, '/', 4); 
Problemi correlati