¿Cómo divido una cadena con múltiples separadores en javascript?

504

¿Cómo divido una cadena con múltiples separadores en JavaScript? Estoy tratando de dividir tanto en comas como en espacios, pero, AFAIK, la función de división de JS solo admite un separador.

mikemaccana
fuente
3
Tuve este problema al tratar de dividir las rutas de archivos que se construyeron con nodejs en Windows. Hubo barras "/" hacia adelante y hacia atrás "\" en la misma ruta a veces.
Fuhrmanator

Respuestas:

707

Pase una expresión regular como parámetro:

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

Editado para agregar:

Puede obtener el último elemento seleccionando la longitud de la matriz menos 1:

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

... y si el patrón no coincide:

>>> bits = "Hello awesome, world!".split(/foo/)
["Hello awesome, world!"]
>>> bits[bits.length - 1]
"Hello awesome, world!"
Aaron Maenpaa
fuente
1
¿Qué estás usando para tu consola js>?
núcleo
44
rhino, la implementación de JavaScript de Mozilla en Java: mozilla.org/rhino (... o "sudo apt-get install rhino").
Aaron Maenpaa
Gracias. Otra pregunta relacionada con esto es lo que tengo que hacer es obtener el último elemento de la matriz dividida. si no hay matriz, debería devolver la cadena thx
2
¿Hay alguna forma de evitar eliminar los separadores cuando se divide con una expresión regular?
Anderson Green el
¿Cómo dividir tanto una cadena "hola mundo" como otro carácter (u otra expresión regular), como el símbolo de la tubería? Intentamos variaciones de las (hello world)|\|cuales todavía no funcionan. ¿Algunas ideas?
loco por natty
183

Puede pasar una expresión regular al operador dividido de Javascript . Por ejemplo:

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

O, si desea permitir que varios separadores juntos actúen como uno solo:

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

(Tienes que usar los parensos que no capturan (? :) porque de lo contrario se vuelven a unir en el resultado. O puedes ser inteligente como Aaron y usar una clase de personaje).

(Ejemplos probados en Safari + FF)

Jesse Rusak
fuente
3
Si necesita que varios caracteres actúen como uno solo, como en, diga "one; #two; #new jersey", simplemente puede pasar la cadena "; #" a la función de división. "one; #two; #new jersey" .split ("; #") [2] === "new jersey"
Oskar Austegard el
Este método funciona mejor que las clases de caracteres si necesita dividir en más de un carácter. Sepáralos |como muestra Jesse.
devios1
Me pregunto si hay una manera de evitar eliminar los separadores al dividir una cadena con una expresión regular: este ejemplo elimina los separadores, pero espero que sea posible dividir una cadena sin eliminarlos.
Anderson Green
1
@AndersonGreen Depende exactamente de lo que quieras; en este caso, hay múltiples separadores, ¿quieres conservarlos todos? Como un artículo separado? Unido al artículo anterior? ¿Proximo articulo? Me parece poco claro. Es posible que desee hacer una nueva pregunta con algunos ejemplos de lo que está buscando.
Jesse Rusak
@JesseRusak Me refería a mantener todos los separadores como elementos separados, de modo que una cadena pudiera ser tokenizada usando una lista de separadores.
Anderson Green el
55

Otro método simple pero efectivo es usar split + join repetidamente.

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

Esencialmente, hacer una división seguida de una unión es como un reemplazo global, por lo que esto reemplaza cada separador con una coma y luego, una vez que todos se reemplazan, se realiza una división final en coma

El resultado de la expresión anterior es:

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

Ampliando esto, también podría colocarlo en una función:

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

Si usa mucho esta funcionalidad, incluso podría valer la pena considerar el ajuste String.prototype.splitpor conveniencia (creo que mi función es bastante segura; la única consideración es la sobrecarga adicional de los condicionales (menores) y el hecho de que carece de una implementación del argumento límite si se pasa una matriz)

Asegúrese de incluir la splitMultifunción si utiliza este enfoque para el siguiente simplemente lo envuelve :). También vale la pena señalar que algunas personas fruncen el ceño al extender los elementos integrados (ya que muchas personas lo hacen mal y pueden ocurrir conflictos), por lo que si tiene dudas, hable con alguien más mayor antes de usar esto o pregunte por 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"] 

¡Disfrutar!

Brian
fuente
3
¿Por qué escribes for(var i = 0; i < tokens.length; i++)y no for(var i = 1; i < tokens.length; i++)?
tic
Me había perdido esa optimización, tienes razón, podemos comenzar tokens[1]a guardar una iteración a medida que tokens[0] == tempcharnos separamos tempchardespués de iterar tokenspara terminar. Actualizaré la respuesta en consecuencia gracias @tic :).
Brian
20

Vamos a mantenerlo simple: (agregar un "[] ​​+" a su RegEx significa "1 o más")

Esto significa que "+" y "{1,}" son lo mismo.

var words = text.split(/[ .:;?!~,`"&|()<>{}\[\]\r\n/\\]+/); // note ' and - are kept
Asher
fuente
2
agregar un "+" al final significa 1 o más
Asher
66
Yo diría que esto es mínimo, no simple
Darryl Hebbes
Para el + y el - :-D, pero también \ s en lugar del carácter en blanco: var words = text.split (/ [\ s.:??~~,`"&|()<>{}\= \ + \ - [] \ r \ n / \] + /);
Didier68
12

Método complicado:

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

fuente
3
esto está mal porque .replace () no reemplaza todos los elementos:/
1
puede cambiar '('para /(/greemplazar todos los (elementos, ges el indicador global de RegExp, por lo que busca todas las apariciones de (no el primero
nombre en clave,
7

Para aquellos de ustedes que desean una mayor personalización en su función de división, escribí un algoritmo recursivo que divide una cadena dada con una lista de caracteres para dividir. Escribí esto antes de ver la publicación anterior. Espero que ayude a algunos programadores frustrados.

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

El ejemplo anterior devuelve: ["people", "and", "other", "things"]

Nota: la flattenfunción se tomó del Código Rosetta

Stephen Sweriduk
fuente
6

Puede agrupar todos los caracteres que desea utilizar como separadores, ya sea de forma individual o colectiva, en una expresión regular y pasarlos a la función de división. Por ejemplo, podrías escribir:

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

Y la salida será:

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

Tal vez debería hacer algún tipo de reemplazo de cadena para convertir un separador en el otro separador para que solo tenga un separador con el que lidiar en su división.

TheTXI
fuente
3

Hola, por ejemplo, si has dividido y reemplazado en String 07:05:45 PM

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

Resultado

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

Aquí hay una nueva forma de lograr lo mismo en 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));

Tenga en cuenta en esta función:

  • No Regex involucrado
  • Devuelve el valor dividido en el mismo orden en que aparece en source

El resultado del código anterior sería:

ingrese la descripción de la imagen aquí

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

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

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

Esto devolverá la cadena sin un carácter especial.

gaurav krishna
fuente
2

Mi refactor de @Brian responde

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
fuente
1

Creo que una de las principales razones por las que necesito esto es dividir las rutas de los archivos en ambos /y \. Es una expresión regular un poco complicada, así que la publicaré aquí como referencia:

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

Creo que es más fácil si especificas lo que quieres dejar, en lugar de lo que quieres eliminar.

Como si quisieras tener solo palabras en inglés, puedes usar algo como esto:

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

Ejemplos (ejecutar fragmento):

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
fuente
1

A partir de la solución @ stephen-sweriduk (¡eso fue lo más interesante para mí!), La modifiqué ligeramente para hacerla más genérica y reutilizable:

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

}

y entonces

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

que devuelve como el original:

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

Una manera fácil de hacer esto es procesar cada carácter de la cadena con cada delimitador y construir una matriz de divisiones:

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

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

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

harr-will
fuente
1

Proporcionaré una implementación clásica para dicha función. El código funciona en casi todas las versiones de JavaScript y de alguna manera es óptimo.

  • No usa expresiones regulares, que es difícil de mantener
  • No utiliza nuevas funciones de JavaScript.
  • No utiliza la invocación múltiple .split () .join () que requiere más memoria de la computadora

Solo código 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);
}

Puede ver el código que se ejecuta en el patio de recreo: https://codeguppy.com/code.html?IJI0E4OGnkyTZnoszAzf

codeguppy
fuente
0

No conozco el rendimiento de RegEx, pero aquí hay otra alternativa para que RegEx aprovecha HashSet nativo y funciona en su lugar con complejidad 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"]
Orhun Alp Oral
fuente
11
Sí, ¿qué tal si realmente pruebas algo que escribes? jsperf.com/slice-vs-custom Esto muestra que su código es en realidad 10 veces más lento en este ejemplo. ¿Qué le dio la idea de que usar 2 veces el corte, 2 veces el concat, 1 división de tiempo, 1 turno de tiempo y sin almacenamiento en caché de longitud es amigable con el rendimiento?
Petar
Actualicé el código, ahora solo hay una cantidad mínima de corte sin cambio, división o etc.
Orhun Alp Oral
0

No es la mejor manera, pero funciona para dividir con separadores / delimitadores múltiples y diferentes

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
fuente
-3

Yo 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"]
Dodi Ivanov
fuente
1
Esto no hace nada con palíndromos , solo palabras.
Nathan Tuggy