2015-05-02 29 views
5

Naprawdę, prawie tak, jak mówi tytuł.Ograniczanie czasów rozdzielania .split(), zamiast obcinania wynikowej tablicy

Powiedzmy, że masz ten ciąg:

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

Teraz, po uruchomieniu theString.split("=") wynik jest ["a", "b", "c", "d"] jak oczekiwano. I oczywiście po uruchomieniu theString.split("=", 2) otrzymujesz ["a", "b"], który po przeczytaniu the MDN page for String#split() ma sens dla mnie.

Jednak zachowanie szukam jest bardziej jak Java String#split(): Zamiast budować tablicę normalnie, po czym zwracając pierwszy n elementy, buduje tablicę pierwszej n-1 zapałki, potem dodaje wszystkie pozostałe znaki jako ostatni element tablicy. Aby uzyskać lepszy opis, patrz: the relevant docs.

Jak mogę uzyskać ten efekt w JavaScript?

Szukam odpowiedzi z najlepszą wydajnością, która działa tak, jak implementacja Java, choć rzeczywisty sposób działania może być inny.

Podpisałbym moją próbę, ale nie wiem, jak to napisać.

Odpowiedz

6

Jeśli chcesz dokładnie równowartość wykonania Java (bez sprawdzania błędów lub klauzul ochronnych itp):

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

Ma to dodatkową zaletę nie obliczeniowej kompletny podział przedtem, jak wspomniano w pytaniu .

+0

Czy możesz dodać szybkie wyjaśnienie, jak to działa? –

+0

@QPaysTaxes I iterować "limit" liczbę razy, i na każdej iteracji używam stateful regex, aby znaleźć następne wystąpienie znaku podziału. Regex pamięta, gdzie znajdował się jego ostatni mecz, a po jego wykonaniu wiem, gdzie jest następny mecz. Dodaję wycinek łańcucha między tymi dwoma lokalizacjami w każdej iteracji. Poza pętlą dodam fragment łańcucha między ostatnim dopasowaniem wyrażenia regularnego i końcem ciągu. –

+2

A ponieważ OP pytał o wydajność - ta implementacja jest około dwa razy szybsza (w Chrome) niż dwie pozostałe. Zaskoczyło mnie! –

3

użyję coś takiego:

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

Co robimy tutaj jest:

  1. Dzielenie ciąg całkowicie
  2. Biorąc pierwsze n-1 elementów, jak opisano .
  3. Ponowne łączenie pozostałych elementów.
  4. Dołączanie do tablicy od kroku 2 i powrót.

Można by pomyśleć, że można połączyć wszystkie te połączenia, ale .push() mutuje tablicę zamiast zwracać nową. Jest ci także łatwiej podążać tą drogą.

+2

hi, może trzeba sprawdzić długość wynikiem podziału jest większy niż N Przed robi kawałek, w przeciwnym razie po prostu zwrócić wynik podziału. – Surely

+0

Dobra uwaga; dodany. –

+0

Podoba mi się ten ze względu na jego prostotę, ale akceptuję drugą, ponieważ (o ile mogę powiedzieć bez benchmarkingu) jest bardziej wydajna. –

2

Jeszcze jedna możliwa realizacja:

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 jest here.

+0

Chociaż nie jestem całkiem pewny co do "długości + 1" - myślę, że to zależy od twoich wymagań - czy chcesz mieć wiodący "separator" w ostatnim elemencie, czy nie. –

+0

Zamień '+ 1' na' + separator.length', w przypadku gdy otrzymasz separator wielokolorowy. –

0

Szukasz czegoś bliżej PHP explode?

Oto metoda Mam opracowany:

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

Metoda ta dzieli ciąg jak normalne, określa, czy mamy uderzyć naszą granicę i wykorzystuje substring dołączyć tekst poza naszym ostatnim ułamku (możemy bezpośredni dostęp do przesunięcia pierwszego znaku poza ostatnim ułamku przez coraz length o join używanego na tablicy z dowolnego pojedynczego znaku jako separatora)

metoda ta jest stosowana tylko jak split:

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

I oczywiście, może to być wirowane jako funkcja TOO:

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