Como faço para dividir uma string com vários separadores em javascript?


504

Como faço para dividir uma string com vários separadores em JavaScript? Estou tentando dividir vírgulas e espaços, mas, AFAIK, a função de divisão do JS suporta apenas um separador.


3
Eu tive esse problema ao tentar dividir caminhos de arquivo que foram construídos com nodejs no Windows. Às vezes, havia barras "/" e back "\" no mesmo caminho.
Fuhrmanator 19/09/14

Respostas:


707

Passe uma regexp como o parâmetro:

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

Editado para adicionar:

Você pode obter o último elemento selecionando o comprimento da matriz menos 1:

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

... e se o padrão não corresponder:

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

1
O que você está usando no seu console js>?
núcleo

4
rhino, a implementação do JavaScript da Mozilla em Java: mozilla.org/rhino (... ou "sudo apt-get install rhino").
Aaron Maenpaa 16/03/09

obrigado. Outra questão relacionada a isso, o que eu preciso fazer é obter o último elemento da matriz dividida. se não há nenhuma disposição que deve retornar o thx corda

2
Existe alguma maneira de evitar a remoção dos separadores ao dividir com uma expressão regular?
Anderson Green

Como dividir tanto uma string "olá mundo" quanto outro caractere (ou outra expressão regular), como o símbolo de barra vertical? Tentei variações das (hello world)|\|quais ainda não funcionaram. Alguma ideia?
Noz sobre natty 28/05

183

Você pode passar uma regex para o operador de divisão do Javascript . Por exemplo:

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

Ou, se você deseja permitir que vários separadores juntos atuem como um só:

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

(Você precisa usar o não-capturante (? :) parens porque, caso contrário, ele será reposto no resultado. Ou você pode ser inteligente como Aaron e usar uma classe de personagem.)

(Exemplos testados no Safari + FF)


3
Se você precisar de vários caracteres para atuar como um, digamos "one; #two; #new jersey", basta passar a string "; #" para a função de divisão. "one; #two; #new jersey" .split ("; #") [2] === "new jersey"
Oskar Austegard,

Esse método funciona melhor que as classes de caracteres se você precisar dividir em mais de um caractere. Separe-os |como mostra Jesse.
devios1

Gostaria de saber se existe uma maneira de evitar remover os separadores ao dividir uma string com uma expressão regular: este exemplo remove os separadores, mas espero que seja possível dividir uma string sem removê-los.
Anderson Green

1
@AndersonGreen Depende exatamente do que você deseja; Nesse caso, existem vários separadores. Deseja mantê-los todos? Como um item separado? Juntou-se ao item anterior? Próximo item? Parece pouco claro para mim. Você pode fazer uma nova pergunta com alguns exemplos do que está procurando.
Jesse Rusak

@JesseRusak, eu quis dizer manter todos os separadores como itens separados, para que uma string possa ser tokenizada usando uma lista de separadores.
Anderson Green

55

Outro método simples, porém eficaz, é usar split + join repetidamente.

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

Essencialmente, fazer uma divisão seguida por uma junção é como uma substituição global; portanto, isso substitui cada separador por vírgula; depois que todos são substituídos, ele faz uma divisão final por vírgula

O resultado da expressão acima é:

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

Expandindo isso, você também pode colocá-lo em uma função:

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 você usa muito essa funcionalidade, pode até valer a pena considerar o agrupamento String.prototype.splitpor conveniência (acho que minha função é razoavelmente segura - a única consideração é a sobrecarga adicional dos condicionais (secundários) e o fato de não haver uma implementação do argumento limite se uma matriz for passada).

Certifique-se de incluir a splitMultifunção se usar esta abordagem para a abaixo simplesmente a envolve :). Também vale a pena notar que algumas pessoas desaprovam a extensão de built-ins (como muitas pessoas fazem errado e podem ocorrer conflitos); portanto, em caso de dúvida, fale com alguém mais experiente antes de usar isso ou pergunte no 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"] 

Aproveitar!


3
Por que você escreve for(var i = 0; i < tokens.length; i++)e não for(var i = 1; i < tokens.length; i++)?
tic

Eu tinha perdido essa otimização, você está certo em que podemos começar tokens[1]a salvar uma iteração tokens[0] == tempchare dividimos tempcharapós a iteração tokenspara concluir. Vou atualizar a resposta de acordo, obrigado @tic :).
Brian

20

Vamos simplificar: (adicione um "[] +" ao seu RegEx significa "1 ou mais")

Isso significa que "+" e "{1,}" são iguais.

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

2
adicionar um "+" no final significa 1 ou mais
Asher

6
Eu diria que este é mínimo, não é simples
Darryl Hebbes

Para o + e o - :-D, mas também \ s em vez do caractere em branco: 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"]

3
isso está errado porque .replace () não substitui todos os elementos #:/

1
você pode mudar '('para /(/gsubstituir todos os (elementos - gé o mundial da bandeira para RegExp - por isso procurar todas as ocorrências de (não primeiro
codename-

7

Para aqueles que desejam mais personalização em sua função de divisão, escrevi um algoritmo recursivo que divide uma determinada string com uma lista de caracteres para dividir. Eu escrevi isso antes de ver o post acima. Espero que ajude alguns 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);

O exemplo acima retorna: ["people", "and", "other", "things"]

Nota: a flattenfunção foi retirada do Código Rosetta


6

Você pode agrupar todos os caracteres que deseja usar como separadores, singular ou coletivamente, em uma expressão regular e passá-los para a função de divisão. Por exemplo, você pode escrever:

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

E a saída será:

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

3

Talvez você deva fazer algum tipo de substituição de string para transformar um separador em outro separador, para ter apenas um separador na sua divisão.


3

Oi, por exemplo, se você dividiu e substituiu na String 07:05:45 PM

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

Resultado

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

3

Aqui está uma nova maneira de obter o mesmo no 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));

Observe nesta função:

  • Nenhum Regex envolvido
  • Retorna o valor dividido na mesma ordem em que aparece em source

O resultado do código acima seria:

insira a descrição da imagem aqui


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

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

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

isso retornará a string sem um caractere especial.


2

Minha refatoração da resposta @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

Acho que uma das principais razões pelas quais eu preciso disso é dividir os caminhos de arquivo em ambos /e \. É um pouco de regex complicado, por isso vou publicá-lo aqui para referência:

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

1

Eu acho que é mais fácil se você especificar o que deseja sair, em vez do que deseja remover.

Como se você quiser ter apenas palavras em inglês, pode usar algo como isto:

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

Exemplos (snippet de execução):

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 partir da solução @ stephen-sweriduk (que foi a mais interessante para mim!), Eu a modifiquei levemente para torná-la mais genérica e reutilizável:

/**
 * 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 depois

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

que retribui como o original:

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

1

Uma maneira fácil de fazer isso é processar cada caractere da string com cada delimitador e criar uma matriz de divisões:

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

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

Devoluções: ["1", "23", "4"]


1

Fornecerei uma implementação clássica para essa função. O código funciona em quase todas as versões do JavaScript e é de alguma forma ideal.

  • Ele não usa regex, o que é difícil de manter
  • Ele não usa novos recursos de JavaScript
  • Ele não usa várias invocações .split () .join () que requerem mais memória do computador

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

Você pode ver o código em execução no playground: https://codeguppy.com/code.html?IJI0E4OGnkyTZnoszAzf


0

Não sei o desempenho do RegEx, mas aqui está outra alternativa para o RegEx aproveita o HashSet nativo e trabalha com complexidade 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
Sim, que tal você realmente testar algo que escreve? jsperf.com/slice-vs-custom Isso mostra que seu código é 10 vezes mais lento neste exemplo. O que lhe deu a idéia de que o uso de 2 vezes fatia, 2 vezes concat, 1 divisão de tempo, 1 turno de tempo e nenhum cache de tamanho é favorável ao desempenho?
Petar

Eu atualizei o código, agora só há quantidade mínima de fatia sem mudança, cisão ou etc.
Orhun Alp Oral

0

Não é a melhor maneira, mas funciona para dividir com vários e diferentes separadores / delimitadores

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

Eu uso o 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
Isso não faz nada com palíndromos , apenas palavras.
Nathan Tuggy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.