Raz podzielić ciąg w javascript?

82

W jaki sposób można podzielić ciąg tylko raz, tj make 1|Ceci n'est pas une pipe: | Ouiparse do: ["1", "Ceci n'est pas une pipe: | Oui"]?

Limit w splicie nie wydaje się pomagać ...

Stavros Korokithakis
źródło

Odpowiedzi:

79

To nie jest ładne podejście, ale działa z przyzwoitą wydajnością:

var string = "1|Ceci n'est pas une pipe: | Oui";
var components = string.split('|');
alert([components.shift(), components.join('|')]​);​​​​​

Oto krótkie demo

Nick Craver
źródło
Myślę, że jest to właściwie lepsze niż wyrażenie regularne. Wybrane jako prawidłowe, dzięki!
Stavros Korokithakis
2
Aby wyjaśnić, dzieli się na N części, a następnie umieszcza pierwszą na liście i dołącza resztę do tej samej listy.
Stavros Korokithakis
Jeśli chcesz uzyskać k tokenów z łańcucha zamiast 1, zrób to samo, co powyżej, z wyjątkiem użycia components.splice (0, k) zamiast components.shift ().
D Coetzee,
Dla tych, którzy zastanawiają się, jak to zrobić z 2 lub więcej uchwytami, możesz użyć shift in a loop lub:components.splice(0,2).slice(0,2)
Ultimater
114

Chciałbyś użyć, String.indexOf('|')aby uzyskać indeks pierwszego wystąpienia „|”.

var i = s.indexOf('|');
var splits = [s.slice(0,i), s.slice(i+1)];
yarmiganosca
źródło
18
Nie tak „zabawne” jak Nick's, ale prawdopodobnie bardziej wydajne. Zwróć również uwagę, że w +1rzeczywistości powinno to być długością łańcucha separatora, jeśli jest więcej niż jeden znak.
devios1
Dlaczego to rozwiązanie jest mniej „przyjemne”?
Bentley4
Dla tych, którzy się zastanawiają, aby zrobić to z 2 lub więcej fragmentami, możesz użyć indexOf w pętli lub:var i = s.split('|',2).join('|').length;//2nd index var splits = [s.slice(0,i).split('|'), s.slice(i+1)];
Ultimater
6
NIE działa to jak split, gdy IndexOf zwróci -1 (np. Jeśli var s = 'string' zwróci ['strin', 'string']). Musiałbyś napisać warunek.
JJJ
14

Możesz użyć:

var splits = str.match(/([^|]*)\|(.*)/);
splits.shift();

Wyrażenie regularne dzieli ciąg na dwie pasujące grupy (w nawiasach), tekst poprzedzający pierwszy | a tekst po. Wtedy myshift wynik, aby pozbyć się całego ciągu match ( splits[0]).

Matthew Flaschen
źródło
1
właściwie powinno to prawdopodobnie zakotwiczyć na początku. jednak javascript regexen wydają się być chciwe.
muhmuhten
6

jedna wkładka i imo, prostsze:

var str = 'I | am super | cool | yea!';
str.split('|').slice(1).join('|');

Zwraca to „Jestem super | super | tak!”

Hassek
źródło
4
Nie o to proszono, szukają też brakującej pierwszej porcji.
SmujMaiku
6

Składnia ES6 pozwala na inne podejście:

function splitOnce(s, on) {
   [first, ...rest] = s.split(on)
   return [first, rest.length > 0? rest.join(on) : null]
}

Który również obsługuje ewentualność łańcucha nie zawierającego a |, zwracając wartość null zamiast pustego ciągu, co jest bardziej wyraźne.

splitOnce("1|Ceci n'est pas une pipe: | Oui", "|")
>>> ["1", "Ceci n'est pas une pipe: | Oui"]

splitOnce("Celui-ci n'a pas de pipe symbol!", "|")
>>> ["Celui-ci n'a pas de pipe symbol!", null]

Pas de pipe? C'est null!

Dodałem tę odpowiedź przede wszystkim po to, aby móc zrobić kalambur na symbolu potoku, ale także po to, aby pochwalić się składnią es6 - to niesamowite, ile osób nadal jej nie używa ...

andyhasit
źródło
3

Spróbuj tego:

function splitOnce(input, splitBy) {
    var fullSplit = input.split(splitBy);
    var retVal = [];
    retVal.push( fullSplit.shift() );
    retVal.push( fullSplit.join( splitBy ) );
    return retVal;
}

var whatever = splitOnce("1|Ceci n'est pas une pipe: | Oui", '|');
Josh the Goods
źródło
3

Jeśli ciąg nie zawiera separatora, rozwiązanie @ NickCraver nadal zwróci tablicę dwóch elementów, z których drugi będzie pusty. Wolę zachowanie pasujące do podziału. Oznacza to, że jeśli ciąg wejściowy nie zawiera separatora, zwraca tylko tablicę z pojedynczym elementem.

var splitOnce = function(str, delim) {
    var components = str.split(delim);
    var result = [components.shift()];
    if(components.length) {
        result.push(components.join(delim));
    }
    return result;
};

splitOnce("a b c d", " "); // ["a", "b c d"]
splitOnce("a", " "); // ["a"]
Raine Revere
źródło
1

Tak samo złe, jak większość dotychczasowych odpowiedzi:

var splits = str.split('|');
splits.splice(1, splits.length - 1, splits.slice(1).join('|'));
wombleton
źródło
0

Alternatywnym, krótkim podejściem, oprócz towarów gdzie indziej, jest wykorzystanie replace()limitu na swoją korzyść.

var str = "1|Ceci n'est pas une pipe: | Oui";
str.replace("|", "aUniquePhraseToSaySplitMe").split("aUniquePhraseToSaySplitMe");

Jak @sreservoir wskazuje w komentarzach, unikalna fraza musi być naprawdę wyjątkowa - nie może znajdować się w źródle, w którym przeprowadzasz ten podział, w przeciwnym razie łańcuch zostanie podzielony na więcej części niż chcesz. Znak niedrukowalny, jak mówi, może zrobić, jeśli uruchamiasz to na podstawie danych wejściowych użytkownika (tj. Wpisywanych w przeglądarce).


źródło
to działa tylko wtedy, gdy „unikalna” fraza jest niepodważalna. w przypadku czytania z pliku tekstowego jest to niemożliwe. jeśli czytasz z przeglądarki, każdy niedrukowalny znak kontrolny, jeśli prawdopodobnie jest w porządku. Tab też działa cuda. w każdym razie „aUniquePhraseToSaySplitMe” jest prawie na pewno częścią danych wejściowych, a zatem jest niebezpieczne.
muhmuhten
Oczywiście masz rację. Mój przykład to tylko przykład mający na celu zwięzłe wyjaśnienie tego, co się dzieje. Uwzględnię twój punkt widzenia w samej odpowiedzi. Dzięki!
Jeśli użyjesz str jako swojej unikalnej frazy, wiesz, że nie może tam być ponownie! : zły uśmiech
Fabio Beltramini
0

Ten jest trochę dłuższy, ale wydaje mi się, że limit powinien:

function split_limit(inString, separator, limit){
    var ary = inString.split(separator);
    var aryOut = ary.slice(0, limit - 1);
    if(ary[limit - 1]){
        aryOut.push(ary.slice(limit - 1).join(separator));
    }
    return aryOut;
}
console.log(split_limit("1|Ceci n'est pas une pipe: | Oui","|", 1));
console.log(split_limit("1|Ceci n'est pas une pipe: | Oui","|", 2));
console.log(split_limit("1|Ceci n'est pas une pipe: | Oui","|", 3));
console.log(split_limit("1|Ceci n'est pas une pipe: | Oui","|", 7));

https://jsfiddle.net/2gyxuo2j/

limit Zero zwraca śmieszne wyniki, ale w imię wydajności pominąłem sprawdzanie. Możesz dodać to jako pierwszy wiersz funkcji, jeśli tego potrzebujesz:

if(limit < 1) return [];
alfadog67
źródło
0

jeśli chcesz użyć „rurociągu”, reduceto twój przyjaciel

const separator = '|'
jsonNode.split(separator)
   .reduce((previous, current, index) =>
    {
        if (index < 2) previous.push(current)
        else previous[1] += `${separator}${current}`
        return previous
    }, [])
    .map((item: string) => (item.trim()))
    .filter((item: string) => (item != ''))
crazyx13th
źródło
0

Bardziej skuteczna metoda:

const str = "1|Ceci n'est pas une pipe: | Oui"

const [head] = str.split('|', 1);

const result = [head, str.substr(head.length + 1)]

console.log(result);

edvard chen
źródło
-1

użyj funkcji wyrażeń regularnych javascript i weź pierwsze przechwycone wyrażenie.

RE prawdopodobnie by wyglądał /^([^|]*)\|/.

w rzeczywistości potrzebujesz tylko /[^|]*/wtedy, gdy potwierdziłeś, że łańcuch jest sformatowany w taki sposób, ze względu na zachłanność wyrażeń regularnych javascript.

muhmuhten
źródło