Wie teile ich eine Zeichenfolge mit mehreren Trennzeichen in Javascript?

504

Wie teile ich eine Zeichenfolge mit mehreren Trennzeichen in JavaScript? Ich versuche, sowohl Kommas als auch Leerzeichen aufzuteilen, aber AFAIK, JS 'Aufteilungsfunktion unterstützt nur ein Trennzeichen.

Mikemaccana
quelle
3
Ich hatte dieses Problem beim Versuch, Dateipfade aufzuteilen, die mit nodejs unter Windows erstellt wurden. Es gab manchmal Schrägstriche vorwärts / rückwärts und rückwärts auf demselben Weg.
Fuhrmanator

Antworten:

707

Übergeben Sie einen regulären Ausdruck als Parameter:

js> "Hello awesome, world!".split(/[\s,]+/)
Hello,awesome,world!

Bearbeitet, um hinzuzufügen:

Sie können das letzte Element erhalten, indem Sie die Länge des Arrays minus 1 auswählen:

>>> bits = "Hello awesome, world!".split(/[\s,]+/)
["Hello", "awesome", "world!"]
>>> bit = bits[bits.length - 1]
"world!"

... und wenn das Muster nicht übereinstimmt:

>>> bits = "Hello awesome, world!".split(/foo/)
["Hello awesome, world!"]
>>> bits[bits.length - 1]
"Hello awesome, world!"
Aaron Maenpaa
quelle
1
Was verwenden Sie für Ihre js> Konsole?
Kern
4
rhino, Mozillas Implementierung von JavaScript in Java: mozilla.org/rhino (... oder "sudo apt-get install rhino").
Aaron Maenpaa
Vielen Dank. Eine andere Frage im Zusammenhang damit, was ich tun muss, ist das letzte Element des geteilten Arrays zu bekommen. Wenn es kein Array gibt, sollte es den String thx
2
Gibt es eine Möglichkeit, das Entfernen der Trennzeichen beim Teilen mit einem regulären Ausdruck zu vermeiden?
Anderson Green
Wie kann man sowohl eine Zeichenfolge "Hallo Welt" als auch ein anderes Zeichen (oder einen anderen regulären Ausdruck) wie das Pipe-Symbol aufteilen? Versuchte Variationen (hello world)|\|davon haben noch nicht ganz funktioniert. Irgendwelche Ideen?
verrückt über natty
183

Sie können einen regulären Ausdruck an den Split-Operator von Javascript übergeben . Zum Beispiel:

"1,2 3".split(/,| /) 
["1", "2", "3"]

Oder wenn Sie zulassen möchten, dass mehrere Trennzeichen zusammen als ein Trennzeichen fungieren:

"1, 2, , 3".split(/(?:,| )+/) 
["1", "2", "3"]

(Sie müssen die nicht erfassenden (? :) Parens verwenden, da sie sonst wieder in das Ergebnis eingefügt werden. Oder Sie können wie Aaron schlau sein und eine Charakterklasse verwenden.)

(Beispiele in Safari + FF getestet)

Jesse Rusak
quelle
3
Wenn Sie mehrere Zeichen benötigen, um als eines zu fungieren, wie in "Eins; # zwei; # neues Trikot", können Sie einfach die Zeichenfolge "; #" an die Teilungsfunktion übergeben. "one; #two; #new jersey" .split ("; #") [2] === "new jersey"
Oskar Austegard
Diese Methode funktioniert besser als Zeichenklassen, wenn Sie mehr als ein Zeichen aufteilen müssen. Trenne sie durch, |wie Jesse zeigt.
Devios1
Ich frage mich, ob es eine Möglichkeit gibt, das Entfernen der Trennzeichen beim Teilen einer Zeichenfolge mit einem regulären Ausdruck zu vermeiden: In diesem Beispiel werden die Trennzeichen entfernt, aber ich hoffe, es ist möglich, eine Zeichenfolge zu teilen, ohne sie zu entfernen.
Anderson Green
1
@AndersonGreen Es kommt genau darauf an, was Sie wollen; In diesem Fall gibt es mehrere Trennzeichen. Möchten Sie sie also alle behalten? Als separater Artikel? Mit dem vorherigen Artikel verbunden? Nächstes Objekt? Es scheint mir unklar. Vielleicht möchten Sie eine neue Frage mit einigen Beispielen stellen, wonach Sie suchen.
Jesse Rusak
@JesseRusak Ich meinte, alle Trennzeichen als separate Elemente zu behalten, damit eine Zeichenfolge mithilfe einer Liste von Trennzeichen tokenisiert werden kann.
Anderson Green
55

Eine andere einfache, aber effektive Methode ist die wiederholte Verwendung von split + join.

"a=b,c:d".split('=').join(',').split(':').join(',').split(',')

Im Wesentlichen ist ein Split gefolgt von einem Join wie ein globales Ersetzen, sodass jedes Trennzeichen durch ein Komma ersetzt wird. Sobald alle ersetzt sind, wird ein endgültiges Teilen durch Komma durchgeführt

Das Ergebnis des obigen Ausdrucks ist:

['a', 'b', 'c', 'd']

Wenn Sie dies erweitern, können Sie es auch in eine Funktion einfügen:

function splitMulti(str, tokens){
        var tempChar = tokens[0]; // We can use the first token as a temporary join character
        for(var i = 1; i < tokens.length; i++){
            str = str.split(tokens[i]).join(tempChar);
        }
        str = str.split(tempChar);
        return str;
}

Verwendungszweck:

splitMulti('a=b,c:d', ['=', ',', ':']) // ["a", "b", "c", "d"]

Wenn Sie diese Funktionalität häufig verwenden, lohnt es sich möglicherweise sogar, eine Umhüllung in Betracht zu ziehen String.prototype.split Einfachheit zu ziehen (ich denke, meine Funktion ist ziemlich sicher - die einzige Überlegung ist der zusätzliche Aufwand für die Bedingungen (geringfügig) und die Tatsache, dass das Limit-Argument nicht implementiert ist wenn ein Array übergeben wird).

Stellen Sie sicher, dass Sie die splitMultiFunktion einschließen , wenn Sie diesen Ansatz wie folgt verwenden: Schließen Sie ihn einfach ein :). Es ist auch erwähnenswert, dass einige Leute die Erweiterung von integrierten Funktionen missbilligen (da viele Leute es falsch machen und Konflikte auftreten können). Wenn Sie Zweifel haben, sprechen Sie mit einer älteren Person, bevor Sie dies verwenden, oder fragen Sie nach SO :)

    var splitOrig = String.prototype.split; // Maintain a reference to inbuilt fn
    String.prototype.split = function (){
        if(arguments[0].length > 0){
            if(Object.prototype.toString.call(arguments[0]) == "[object Array]" ) { // Check if our separator is an array
                return splitMulti(this, arguments[0]);  // Call splitMulti
            }
        }
        return splitOrig.apply(this, arguments); // Call original split maintaining context
    };

Verwendungszweck:

var a = "a=b,c:d";
    a.split(['=', ',', ':']); // ["a", "b", "c", "d"]

// Test to check that the built-in split still works (although our wrapper wouldn't work if it didn't as it depends on it :P)
        a.split('='); // ["a", "b,c:d"] 

Genießen!

Brian
quelle
3
Warum schreibst du for(var i = 0; i < tokens.length; i++)und nicht for(var i = 1; i < tokens.length; i++)?
Tic
Ich hatte diese Optimierung verpasst. Sie haben Recht, wir können damit beginnen tokens[1], eine Iteration zu speichern, tokens[0] == tempcharund wir teilen uns tempcharnach der Iteration auf tokens, um den Vorgang abzuschließen . Ich werde die Antwort entsprechend aktualisieren, danke @tic :).
Brian
20

Lassen Sie es uns einfach halten: (Fügen Sie Ihrem RegEx ein "[] ​​+" hinzu, was "1 oder mehr" bedeutet)

Dies bedeutet, dass "+" und "{1,}" gleich sind.

var words = text.split(/[ .:;?!~,`"&|()<>{}\[\]\r\n/\\]+/); // note ' and - are kept
Asher
quelle
2
Ein "+" am Ende bedeutet 1 oder mehr
Asher
6
Ich würde sagen, das ist minimal, nicht einfach
Darryl Hebbes
Für das + und das - :-D, aber auch \ s anstelle des leeren Zeichens: var words = text.split (/ [\ s.:;?!~,`"&|()<> { \ + \ - [] \ r \ n / \] + /);
Didier68
12

Tricky Methode:

var s = "dasdnk asd, (naks) :d skldma";
var a = s.replace('(',' ').replace(')',' ').replace(',',' ').split(' ');
console.log(a);//["dasdnk", "asd", "naks", ":d", "skldma"]

quelle
3
Dies ist falsch, weil .replace () nicht alle Elemente ersetzt:/
1
Sie können '('für ändern /(/g, um alle (Elemente zu ersetzen - gist das globale Flag für RegExp - so sucht es nach allen Vorkommen von (nicht ersten
Codename
7

Für diejenigen unter Ihnen, die mehr Anpassungsmöglichkeiten in ihrer Aufteilungsfunktion wünschen, habe ich einen rekursiven Algorithmus geschrieben, der eine bestimmte Zeichenfolge mit einer Liste von Zeichen aufteilt, auf die aufgeteilt werden soll. Ich habe das geschrieben, bevor ich den obigen Beitrag gesehen habe. Ich hoffe, es hilft einigen frustrierten Programmierern.

splitString = function(string, splitters) {
    var list = [string];
    for(var i=0, len=splitters.length; i<len; i++) {
        traverseList(list, splitters[i], 0);
    }
    return flatten(list);
}

traverseList = function(list, splitter, index) {
    if(list[index]) {
        if((list.constructor !== String) && (list[index].constructor === String))
            (list[index] != list[index].split(splitter)) ? list[index] = list[index].split(splitter) : null;
        (list[index].constructor === Array) ? traverseList(list[index], splitter, 0) : null;
        (list.constructor === Array) ? traverseList(list, splitter, index+1) : null;    
    }
}

flatten = function(arr) {
    return arr.reduce(function(acc, val) {
        return acc.concat(val.constructor === Array ? flatten(val) : val);
    },[]);
}

var stringToSplit = "people and_other/things";
var splitList = [" ", "_", "/"];
splitString(stringToSplit, splitList);

Beispiel oben gibt zurück: ["people", "and", "other", "things"]

Hinweis: Die flattenFunktion wurde aus dem Rosetta-Code übernommen

Stephen Sweriduk
quelle
6

Sie können einfach alle Zeichen, die Sie als Trennzeichen verwenden möchten, einzeln oder gemeinsam zu einem regulären Ausdruck zusammenfassen und an die Teilungsfunktion übergeben. Zum Beispiel könnten Sie schreiben:

console.log( "dasdnk asd, (naks) :d skldma".split(/[ \(,\)]+/) );

Und die Ausgabe wird sein:

["dasdnk", "asd", "naks", ":d", "skldma"]
PeterKA
quelle
3

Vielleicht sollten Sie eine Art Zeichenfolgen ersetzen, um ein Trennzeichen in das andere zu trennen, damit Sie dann nur ein Trennzeichen in Ihrem Split haben.

TheTXI
quelle
3

Hallo zum Beispiel, wenn Sie in String 07:05:45 PM geteilt und ersetzt haben

var hour = time.replace("PM", "").split(":");

Ergebnis

[ '07', '05', '45' ]
Ezequiel García
quelle
3

Hier ist ein neuer Weg, um dasselbe in ES6 zu erreichen :

function SplitByString(source, splitBy) {
  var splitter = splitBy.split('');
  splitter.push([source]); //Push initial value

  return splitter.reduceRight(function(accumulator, curValue) {
    var k = [];
    accumulator.forEach(v => k = [...k, ...v.split(curValue)]);
    return k;
  });
}

var source = "abc,def#hijk*lmn,opq#rst*uvw,xyz";
var splitBy = ",*#";
console.log(SplitByString(source, splitBy));

Bitte beachten Sie in dieser Funktion:

  • Kein Regex beteiligt
  • Gibt den geteilten Wert in derselben Reihenfolge zurück, in der er angezeigt wird source

Das Ergebnis des obigen Codes wäre:

Geben Sie hier die Bildbeschreibung ein

Vishnu
quelle
2
a = "a=b,c:d"

array = ['=',',',':'];

for(i=0; i< array.length; i++){ a= a.split(array[i]).join(); }

Dadurch wird die Zeichenfolge ohne ein spezielles Zeichen zurückgegeben.

gaurav krishna
quelle
2

Mein Refaktor von @Brian antwortet

var string = 'and this is some kind of information and another text and simple and some egample or red or text';
var separators = ['and', 'or'];

function splitMulti(str, separators){
            var tempChar = 't3mp'; //prevent short text separator in split down
            
            //split by regex e.g. \b(or|and)\b
            var re = new RegExp('\\b(' + separators.join('|') + ')\\b' , "g");
            str = str.replace(re, tempChar).split(tempChar);
            
            // trim & remove empty
            return str.map(el => el.trim()).filter(el => el.length > 0);
}

console.log(splitMulti(string, separators))

JanuszO
quelle
1

Ich finde, dass einer der Hauptgründe, warum ich dies brauche, darin besteht, Dateipfade auf beiden /und zu teilen \. Es ist ein bisschen knifflig, also werde ich es hier als Referenz posten:

var splitFilePath = filePath.split(/[\/\\]/);
AlliterativeAlice
quelle
1

Ich denke, es ist einfacher, wenn Sie angeben, was Sie verlassen möchten, anstatt was Sie entfernen möchten.

Als ob Sie nur englische Wörter haben möchten, können Sie Folgendes verwenden:

text.match(/[a-z'\-]+/gi);

Beispiele (Snippet ausführen):

var R=[/[a-z'\-]+/gi,/[a-z'\-\s]+/gi];
var s=document.getElementById('s');
for(var i=0;i<R.length;i++)
 {
  var o=document.createElement('option');
  o.innerText=R[i]+'';
  o.value=i;
  s.appendChild(o);
 }
var t=document.getElementById('t');
var r=document.getElementById('r');

s.onchange=function()
 {
  r.innerHTML='';
  var x=s.value;
  if((x>=0)&&(x<R.length))
   x=t.value.match(R[x]);
  for(i=0;i<x.length;i++)
   {
    var li=document.createElement('li');
    li.innerText=x[i];
    r.appendChild(li);
   }
 }
<textarea id="t" style="width:70%;height:12em">even, test; spider-man

But saying o'er what I have said before:
My child is yet a stranger in the world;
She hath not seen the change of fourteen years,
Let two more summers wither in their pride,
Ere we may think her ripe to be a bride.

—Shakespeare, William. The Tragedy of Romeo and Juliet</textarea>

<p><select id="s">
 <option selected>Select a regular expression</option>
 <!-- option value="1">/[a-z'\-]+/gi</option>
 <option value="2">/[a-z'\-\s]+/gi</option -->
</select></p>
 <ol id="r" style="display:block;width:auto;border:1px inner;overflow:scroll;height:8em;max-height:10em;"></ol>
</div>

ESL
quelle
1

Ausgehend von der @ stephen-sweriduk-Lösung (das war für mich interessanter!) Habe ich sie leicht modifiziert, um sie allgemeiner und wiederverwendbarer zu machen:

/**
 * Adapted from: http://stackoverflow.com/questions/650022/how-do-i-split-a-string-with-multiple-separators-in-javascript
*/
var StringUtils = {

  /**
   * Flatten a list of strings
   * http://rosettacode.org/wiki/Flatten_a_list
   */
  flatten : function(arr) {
    var self=this;
    return arr.reduce(function(acc, val) {
        return acc.concat(val.constructor === Array ? self.flatten(val) : val);
    },[]);
  },

  /**
   * Recursively Traverse a list and apply a function to each item
   * @param list array
   * @param expression Expression to use in func
   * @param func function of (item,expression) to apply expression to item
   *
   */
  traverseListFunc : function(list, expression, index, func) {
    var self=this;
    if(list[index]) {
        if((list.constructor !== String) && (list[index].constructor === String))
            (list[index] != func(list[index], expression)) ? list[index] = func(list[index], expression) : null;
        (list[index].constructor === Array) ? self.traverseListFunc(list[index], expression, 0, func) : null;
        (list.constructor === Array) ? self.traverseListFunc(list, expression, index+1, func) : null;
    }
  },

  /**
   * Recursively map function to string
   * @param string
   * @param expression Expression to apply to func
   * @param function of (item, expressions[i])
   */
  mapFuncToString : function(string, expressions, func) {
    var self=this;
    var list = [string];
    for(var i=0, len=expressions.length; i<len; i++) {
        self.traverseListFunc(list, expressions[i], 0, func);
    }
    return self.flatten(list);
  },

  /**
   * Split a string
   * @param splitters Array of characters to apply the split
   */
  splitString : function(string, splitters) {
    return this.mapFuncToString(string, splitters, function(item, expression) {
      return item.split(expression);
    })
  },

}

und dann

var stringToSplit = "people and_other/things";
var splitList = [" ", "_", "/"];
var splittedString=StringUtils.splitString(stringToSplit, splitList);
console.log(splitList, stringToSplit, splittedString);

das gibt als original zurück:

[ ' ', '_', '/' ] 'people and_other/things' [ 'people', 'and', 'other', 'things' ]
loretoparisi
quelle
1

Eine einfache Möglichkeit, dies zu tun, besteht darin, jedes Zeichen der Zeichenfolge mit jedem Trennzeichen zu verarbeiten und ein Array der Teilungen zu erstellen:

splix = function ()
{
  u = [].slice.call(arguments); v = u.slice(1); u = u[0]; w = [u]; x = 0;

  for (i = 0; i < u.length; ++i)
  {
    for (j = 0; j < v.length; ++j)
    {
      if (u.slice(i, i + v[j].length) == v[j])
      {
        y = w[x].split(v[j]); w[x] = y[0]; w[++x] = y[1];
      };
    };
  };

  return w;
};

Verwendungszweck: splix(string, delimiters...)

Beispiel: splix("1.23--4", ".", "--")

Kehrt zurück: ["1", "23", "4"]

Harr-Will
quelle
1

Ich werde eine klassische Implementierung für eine solche Funktion bereitstellen. Der Code funktioniert in fast allen Versionen von JavaScript und ist irgendwie optimal.

  • Es wird kein regulärer Ausdruck verwendet, der schwer zu pflegen ist
  • Es werden keine neuen Funktionen von JavaScript verwendet
  • Es werden nicht mehrere .split () .join () -Aufrufe verwendet, die mehr Computerspeicher erfordern

Nur reiner Code:

var text = "Create a function, that will return an array (of string), with the words inside the text";

println(getWords(text));

function getWords(text)
{
    let startWord = -1;
    let ar = [];

    for(let i = 0; i <= text.length; i++)
    {
        let c = i < text.length ? text[i] : " ";

        if (!isSeparator(c) && startWord < 0)
        {
            startWord = i;
        }

        if (isSeparator(c) && startWord >= 0)
        {
            let word = text.substring(startWord, i);
            ar.push(word);

            startWord = -1;
        }
    }

    return ar;
}

function isSeparator(c)
{
    var separators = [" ", "\t", "\n", "\r", ",", ";", ".", "!", "?", "(", ")"];
    return separators.includes(c);
}

Sie können den Code auf dem Spielplatz sehen: https://codeguppy.com/code.html?IJI0E4OGnkyTZnoszAzf

Codeguppy
quelle
0

Ich kenne die Leistung von RegEx nicht, aber hier ist eine weitere Alternative für RegEx, die natives HashSet nutzt und stattdessen in O-Komplexität (max (str.length, delimeter.length)) arbeitet:

var multiSplit = function(str,delimiter){
    if (!(delimiter instanceof Array))
        return str.split(delimiter);
    if (!delimiter || delimiter.length == 0)
        return [str];
    var hashSet = new Set(delimiter);
    if (hashSet.has(""))
        return str.split("");
    var lastIndex = 0;
    var result = [];
    for(var i = 0;i<str.length;i++){
        if (hashSet.has(str[i])){
            result.push(str.substring(lastIndex,i));
            lastIndex = i+1;
        }
    }
    result.push(str.substring(lastIndex));
    return result;
}

multiSplit('1,2,3.4.5.6 7 8 9',[',','.',' ']);
// Output: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]

multiSplit('1,2,3.4.5.6 7 8 9',' ');
// Output: ["1,2,3.4.5.6", "7", "8", "9"]
Orhun Alp Oral
quelle
11
Ja, wie wäre es, wenn Sie tatsächlich etwas testen, das Sie schreiben? jsperf.com/slice-vs-custom Dies zeigt, dass Ihr Code in diesem Beispiel tatsächlich zehnmal langsamer ist. Was hat Sie auf die Idee gebracht, dass die Verwendung von 2-maligem Slice, 2-maligem Concat, 1-maligem Split, 1-maliger Verschiebung und ohne Längen-Caching leistungsfreundlich ist?
Petar
Ich habe den Code aktualisiert, jetzt gibt es nur noch eine minimale Menge an Slice ohne Shift, Split oder etc.
Orhun Alp Oral
0

Nicht der beste Weg, aber funktioniert mit mehreren und verschiedenen Trennzeichen / Trennzeichen

html

<button onclick="myFunction()">Split with Multiple and Different seperators/delimiters</button>
<p id="demo"></p>

Javascript

<script>
function myFunction() {

var str = "How : are | you doing : today?";
var res = str.split(' | ');

var str2 = '';
var i;
for (i = 0; i < res.length; i++) { 
    str2 += res[i];

    if (i != res.length-1) {
      str2 += ",";
    }
}
var res2 = str2.split(' : ');

//you can add countless options (with or without space)

document.getElementById("demo").innerHTML = res2;
</script>
Stavros
quelle
-3

Ich benutze Regexp:

str =  'Write a program that extracts from a given text all palindromes, e.g. "ABBA", "lamal", "exe".';

var strNew = str.match(/\w+/g);

// Output: ["Write", "a", "program", "that", "extracts", "from", "a", "given", "text", "all", "palindromes", "e", "g", "ABBA", "lamal", "exe"]
Dodi Ivanov
quelle
1
Das macht nichts mit Palindromen , nur mit Worten.
Nathan Tuggy