Come divido una stringa con più separatori in javascript?


504

Come divido una stringa con più separatori in JavaScript? Sto cercando di dividere su virgole e spazi ma, AFAIK, la funzione di divisione di JS supporta solo un separatore.


3
Ho avuto questo problema cercando di dividere i percorsi dei file che sono stati costruiti con nodejs sotto Windows. A volte c'erano "/" e indietro "\" barre nello stesso percorso.
Fuhrmanator,

Risposte:


707

Passa una regexp come parametro:

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

Modificato per aggiungere:

È possibile ottenere l'ultimo elemento selezionando la lunghezza dell'array meno 1:

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

... e se il modello non corrisponde:

>>> bits = "Hello awesome, world!".split(/foo/)
["Hello awesome, world!"]
>>> bits[bits.length - 1]
"Hello awesome, world!"

1
Cosa stai usando per la tua console js>?
core

4
rhino, l'implementazione di JavaScript di Java in Java: mozilla.org/rhino (... o "sudo apt-get install rhino").
Aaron Maenpaa,

Grazie. un'altra domanda relativa a ciò che devo fare è ottenere l'ultimo elemento dell'array suddiviso. se non c'è un array dovrebbe restituire la stringa thx

2
Esiste un modo per evitare di rimuovere i separatori quando si divide con un'espressione regolare?
Anderson Green,

Come dividere sia per una stringa "ciao mondo" che per un altro personaggio (o altra regex), come il simbolo della pipa? Le variazioni provate (hello world)|\|non hanno ancora funzionato. Qualche idea?
pazzo per il natty del

183

È possibile passare una regex nell'operatore split di Javascript . Per esempio:

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

Oppure, se si desidera consentire a più separatori insieme di agire come uno solo:

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

(Devi usare le parentesi non catturanti (? :) perché altrimenti vengono ricucite nel risultato. O puoi essere intelligente come Aaron e usare una classe di personaggi.)

(Esempi testati in Safari + FF)


3
Se hai bisogno di più personaggi per agire come uno, come in, dì "uno; # due; #nuova maglia", puoi semplicemente passare la stringa "; #" alla funzione divisa. "one; #two; #new jersey" .split ("; #") [2] === "new jersey"
Oskar Austegard,

Questo metodo funziona meglio delle classi di caratteri se è necessario suddividere più di un carattere. Separali da |come mostra Jesse.
devios1

Mi chiedo se c'è un modo per evitare di rimuovere i separatori quando si divide una stringa con un'espressione regolare: questo esempio rimuove i separatori, ma spero sia possibile dividere una stringa senza rimuoverli.
Anderson Green,

1
@AndersonGreen Dipende esattamente da cosa vuoi; in questo caso, ci sono più separatori, quindi vuoi tenerli tutti? Come articolo separato? Ti sei unito all'elemento precedente? Prossimo articolo? Mi sembra poco chiaro. Potresti voler fare una nuova domanda con alcuni esempi di ciò che stai cercando.
Jesse Rusak,

@JesseRusak Volevo dire mantenere tutti i separatori come elementi separati, in modo che una stringa potesse essere tokenizzata usando un elenco di separatori.
Anderson Green,

55

Un altro metodo semplice ma efficace è utilizzare ripetutamente split + join.

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

Fondamentalmente fare una divisione seguita da un join è come una sostituzione globale, quindi questo sostituisce ogni separatore con una virgola, quindi una volta che tutti sono stati sostituiti, esegue una divisione finale su una virgola

Il risultato dell'espressione precedente è:

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

Espandendo su questo potresti anche metterlo in una funzione:

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

Uso:

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

Se usi molto questa funzionalità, potrebbe anche valere la pena considerare la possibilità di avvolgerla String.prototype.splitper comodità (penso che la mia funzione sia abbastanza sicura - l'unica considerazione è l'overhead aggiuntivo dei condizionali (minore) e il fatto che manca un'implementazione dell'argomento limite se viene passato un array).

Assicurati di includere la splitMultifunzione se si utilizza semplicemente questo approccio al di sotto :) Vale anche la pena notare che alcune persone aggrottano le sopracciglia per estendere i built-in (poiché molte persone lo fanno male e possono verificarsi conflitti) quindi in caso di dubbio parla con qualcuno più senior prima di utilizzare questo o chiedi su 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
    };

Uso:

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

Godere!


3
Perché scrivi for(var i = 0; i < tokens.length; i++)e no for(var i = 1; i < tokens.length; i++)?
tic,

Avevo perso quell'ottimizzazione, hai ragione, possiamo iniziare a tokens[1]salvare un'iterazione tokens[0] == tempchare ci siamo separati tempchardopo aver ripetuto l'iterazione tokensper finire. Aggiornerò la risposta di conseguenza grazie @tic :).
Brian,

20

Semplificiamo: (aggiungi un "[] ​​+" al tuo RegEx significa "1 o più")

Ciò significa che "+" e "{1,}" sono uguali.

var words = text.split(/[ .:;?!~,`"&|()<>{}\[\]\r\n/\\]+/); // note ' and - are kept

2
aggiungere un "+" alla fine significa 1 o più
Asher

6
Direi che questo è minimo, non semplice
Darryl Hebbes,

Per + e - :-D, ma anche \ s invece del carattere vuoto: var words = text.split (/ [\ s.:;?!~,`"&|()<>{}\= \ + \ - [] \ r \ n / \] + /);
Didier68

12

Metodo ingannevole:

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

3
questo è sbagliato perché .replace () non sostituisce tutti gli elementi:/

1
puoi cambiare '('per /(/gsostituire tutti gli (elementi - gè la bandiera globale per RegExp - quindi cerca tutte le occorrenze di (non prima
nome in codice

7

Per quelli di voi che desiderano una maggiore personalizzazione nella loro funzione di divisione, ho scritto un algoritmo ricorsivo che divide una determinata stringa con un elenco di caratteri su cui dividere. Ho scritto questo prima di vedere il post sopra. Spero che aiuti alcuni programmatori frustrati.

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

L'esempio sopra restituisce: ["people", "and", "other", "things"]

Nota: la flattenfunzione è stata presa dal codice Rosetta


6

Potresti semplicemente raggruppare tutti i personaggi che vuoi usare come separatori singolarmente o collettivamente in un'espressione regolare e passarli alla funzione di divisione. Ad esempio potresti scrivere:

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

E l'output sarà:

["dasdnk", "asd", "naks", ":d", "skldma"]

3

Forse dovresti fare una sorta di sostituzione della stringa per trasformare un separatore nell'altro separatore in modo da avere un solo separatore da gestire nella tua divisione.


3

Salve, ad esempio, se hai diviso e sostituito in String 07:05:45 PM

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

Risultato

[ '07', '05', '45' ]

3

Ecco un nuovo modo per raggiungere lo stesso in ES6 :

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

Si prega di notare in questa funzione:

  • Nessun Regex coinvolto
  • Restituisce il valore diviso nello stesso ordine in cui appare source

Il risultato del codice sopra sarebbe:

inserisci qui la descrizione dell'immagine


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

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

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

questo restituirà la stringa senza un carattere speciale.


2

Il mio refactor della risposta di @Brian

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


1

Trovo che uno dei motivi principali per cui ho bisogno è quello di dividere i percorsi dei file su entrambi /e \. È un po 'una regex complicata, quindi la posterò qui come riferimento:

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

1

Penso che sia più facile se specifichi ciò che vuoi lasciare, invece di ciò che vuoi rimuovere.

Come se volessi avere solo parole inglesi, puoi usare qualcosa del genere:

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

Esempi (esegui snippet):

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>


1

A partire dalla soluzione @ stephen-sweriduk (che è stata la più interessante per me!), L'ho leggermente modificata per renderla più generica e riutilizzabile:

/**
 * 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);
    })
  },

}

e poi

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

che restituisce come l'originale:

[ ' ', '_', '/' ] 'people and_other/things' [ 'people', 'and', 'other', 'things' ]

1

Un modo semplice per farlo è quello di elaborare ogni carattere della stringa con ciascun delimitatore e creare una matrice delle divisioni:

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

Uso: splix(string, delimiters...)

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

Ritorna: ["1", "23", "4"]


1

Fornirò un'implementazione classica per una tale funzione. Il codice funziona in quasi tutte le versioni di JavaScript ed è in qualche modo ottimale.

  • Non usa regex, che è difficile da mantenere
  • Non utilizza nuove funzionalità di JavaScript
  • Non utilizza più invocazioni .split () .join () che richiedono più memoria del computer

Solo codice puro:

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

Puoi vedere il codice in esecuzione nel parco giochi: https://codeguppy.com/code.html?IJI0E4OGnkyTZnoszAzf


0

Non conosco le prestazioni di RegEx, ma ecco un'altra alternativa per RegEx che sfrutta HashSet nativo e funziona invece nella complessità O (max (str.length, delimeter.length)):

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

11
Sì, che ne dici di provare effettivamente qualcosa che scrivi? jsperf.com/slice-vs-custom Questo dimostra che il tuo codice è in realtà 10 volte più lento in questo esempio. Cosa ti ha dato l'idea che l'utilizzo della suddivisione in 2 tempi, 2 volte concat, 1 divisione temporale, 1 spostamento temporale e nessuna memorizzazione nella cache della lunghezza siano ottimali per le prestazioni?
Petar,

Ho aggiornato il codice, ora c'è solo una quantità minima di slice senza spostamento, divisione o ecc.
Orhun Alp Oral

0

Non è il modo migliore ma funziona per dividere con separatori / delimitatori multipli e diversi

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>

-3

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

1
Questo non fa nulla con i palindromi , solo parole.
Nathan Tuggy,
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.