Comment diviser une chaîne avec plusieurs séparateurs en javascript?

504

Comment diviser une chaîne avec plusieurs séparateurs en JavaScript? J'essaie de séparer les virgules et les espaces, mais, AFAIK, la fonction de fractionnement de JS ne prend en charge qu'un seul séparateur.

mikemaccana
la source
3
J'ai eu ce problème en essayant de diviser les chemins de fichiers qui ont été construits avec nodejs sous windows. Il y avait parfois des barres obliques "/" et arrière "\" dans le même chemin.
Fuhrmanator

Réponses:

707

Passez une expression rationnelle comme paramètre:

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

Modifié pour ajouter:

Vous pouvez obtenir le dernier élément en sélectionnant la longueur du tableau moins 1:

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

... et si le motif ne correspond pas:

>>> bits = "Hello awesome, world!".split(/foo/)
["Hello awesome, world!"]
>>> bits[bits.length - 1]
"Hello awesome, world!"
Aaron Maenpaa
la source
1
Qu'utilisez-vous pour votre console js>?
core
4
rhino, implémentation de JavaScript par Mozilla en Java: mozilla.org/rhino (... ou "sudo apt-get install rhino").
Aaron Maenpaa
Merci. une autre question liée à ce que je dois faire est d'obtenir le dernier élément du tableau divisé. s'il n'y a pas de tableau, il devrait retourner la chaîne thx
2
Existe-t-il un moyen d'éviter de supprimer les séparateurs lors du fractionnement avec une expression régulière?
Anderson Green
Comment diviser à la fois une chaîne "hello world" ainsi qu'un autre caractère (ou autre regex), comme le symbole de la pipe? Des variations éprouvées (hello world)|\|qui ne fonctionnaient pas encore tout à fait. Des idées?
noisette sur natty
183

Vous pouvez passer une expression régulière dans l'opérateur de division de Javascript . Par exemple:

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

Ou, si vous souhaitez autoriser plusieurs séparateurs ensemble à agir comme un seul:

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

(Vous devez utiliser les parens non capturants (? :) car sinon, ils sont épissés dans le résultat. Ou vous pouvez être intelligent comme Aaron et utiliser une classe de caractères.)

(Exemples testés dans Safari + FF)

Jesse Rusak
la source
3
Si vous avez besoin de plusieurs caractères pour agir comme un seul, comme dans, dites "un; #deux; #nouveau maillot", vous pouvez simplement passer la chaîne "; #" à la fonction de partage. "one; #two; #new jersey" .split ("; #") [2] === "new jersey"
Oskar Austegard
Cette méthode fonctionne mieux que les classes de caractères si vous devez vous séparer sur plusieurs caractères. Séparez-les par |comme le montre Jesse.
devios1
Je me demande s'il existe un moyen d'éviter de supprimer les séparateurs lors du fractionnement d'une chaîne avec une expression régulière: cet exemple supprime les séparateurs, mais j'espère qu'il est possible de diviser une chaîne sans les supprimer.
Anderson Green
1
@AndersonGreen Cela dépend exactement de ce que vous voulez; dans ce cas, il y a plusieurs séparateurs, voulez-vous donc tous les conserver? En tant qu'élément distinct? Joint à l'élément précédent? Prochain point? Cela me semble peu clair. Vous voudrez peut-être poser une nouvelle question avec quelques exemples de ce que vous recherchez.
Jesse Rusak
@JesseRusak Je voulais dire garder tous les séparateurs en tant qu'éléments séparés, afin qu'une chaîne puisse être symbolisée à l'aide d'une liste de séparateurs.
Anderson Green
55

Une autre méthode simple mais efficace consiste à utiliser split + join à plusieurs reprises.

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

Essentiellement, faire un fractionnement suivi d'une jointure est comme un remplacement global, ce qui remplace chaque séparateur par une virgule, puis une fois tous remplacés, il effectue un fractionnement final sur une virgule

Le résultat de l'expression ci-dessus est:

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

En développant cela, vous pouvez également le placer dans une fonction:

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

Usage:

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

Si vous utilisez beaucoup cette fonctionnalité, il pourrait même être utile d'envisager un emballage String.prototype.splitpour plus de commodité (je pense que ma fonction est assez sûre - la seule considération est le surcoût supplémentaire des conditions (mineur) et le fait qu'il manque une implémentation de l'argument limit si un tableau est passé).

Assurez-vous d'inclure la splitMultifonction si vous utilisez cette approche ci-dessous pour l'enrouler simplement :). Il convient également de noter que certaines personnes désapprouvent l'extension des fonctionnalités intégrées (car de nombreuses personnes le font mal et des conflits peuvent survenir), donc en cas de doute, parlez à quelqu'un de plus âgé avant d'utiliser cela ou demandez SO 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
    };

Usage:

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

Prendre plaisir!

Brian
la source
3
Pourquoi écrivez-vous for(var i = 0; i < tokens.length; i++)et non for(var i = 1; i < tokens.length; i++)?
tic
J'avais raté cette optimisation, vous avez raison, nous pouvons commencer à tokens[1]enregistrer une itération sous tokens[0] == tempcharet nous nous tempcharséparons après avoir répété tokenspour terminer. Je mettrai à jour la réponse en conséquence merci @tic :).
Brian
20

Permet de rester simple: (ajouter un "[] ​​+" à votre RegEx signifie "1 ou plus")

Cela signifie que "+" et "{1,}" sont identiques.

var words = text.split(/[ .:;?!~,`"&|()<>{}\[\]\r\n/\\]+/); // note ' and - are kept
Asher
la source
2
ajouter un "+" à la fin signifie 1 ou plus
Asher
6
Je dirais que c'est minimal, pas simple
Darryl Hebbes
Pour le + et le - :-D, mais aussi \ s au lieu du caractère vierge: var words = text.split (/ [\ s.:;?!~,`"&|()<>{}\= \ + \ - [] \ r \ n / \] + /);
Didier68
12

Méthode délicate:

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

la source
3
c'est faux car .replace () ne remplace pas tous les éléments:/
1
vous pouvez changer '('pour /(/gremplacer tous les (éléments - gest le drapeau global pour RegExp - donc il recherche toutes les occurrences de (pas le premier
nom de code
7

Pour ceux d'entre vous qui souhaitent plus de personnalisation dans leur fonction de fractionnement, j'ai écrit un algorithme récursif qui fractionne une chaîne donnée avec une liste de caractères à fractionner. J'ai écrit ceci avant de voir le post ci-dessus. J'espère que cela aide certains programmeurs frustrés.

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'exemple ci-dessus renvoie: ["people", "and", "other", "things"]

Remarque: la flattenfonction provient du code Rosetta

Stephen Sweriduk
la source
6

Vous pouvez simplement regrouper tous les caractères que vous souhaitez utiliser comme séparateurs soit individuellement soit collectivement dans une expression régulière et les transmettre à la fonction de fractionnement. Par exemple, vous pourriez écrire:

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

Et la sortie sera:

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

Vous devriez peut-être faire une sorte de remplacement de chaîne pour transformer un séparateur en l'autre séparateur afin que vous n'ayez alors qu'un seul séparateur à traiter dans votre fractionnement.

TheTXI
la source
3

Salut par exemple si vous avez divisé et remplacé dans String 07:05:45 PM

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

Résultat

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

Voici une nouvelle façon d'y parvenir dans 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));

Veuillez noter dans cette fonction:

  • Aucun Regex impliqué
  • Renvoie la valeur fractionnée dans le même ordre que celui indiqué dans source

Le résultat du code ci-dessus serait:

entrez la description de l'image ici

Vishnu
la source
2
a = "a=b,c:d"

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

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

cela retournera la chaîne sans caractère spécial.

gaurav krishna
la source
2

Mon refactor de @Brian réponse

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
la source
1

Je trouve que l'une des principales raisons pour lesquelles j'ai besoin de cela est de diviser les chemins de fichiers sur /et \. C'est un peu une expression rationnelle difficile, donc je vais le poster ici pour référence:

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

Je pense que c'est plus facile si vous spécifiez ce que vous voulez laisser, au lieu de ce que vous voulez supprimer.

Comme si vous ne voulez avoir que des mots anglais, vous pouvez utiliser quelque chose comme ceci:

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

Exemples (exécuter un extrait):

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
la source
1

À partir de la solution @ stephen-sweriduk (qui était la plus intéressante pour moi!), Je l'ai légèrement modifiée pour la rendre plus générique et réutilisable:

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

}

et alors

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

qui redonne comme l'original:

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

Un moyen simple de le faire consiste à traiter chaque caractère de la chaîne avec chaque délimiteur et à créer un tableau des divisions:

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

Usage: splix(string, delimiters...)

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

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

harr-will
la source
1

Je vais fournir une implémentation classique pour une telle fonction. Le code fonctionne dans presque toutes les versions de JavaScript et est en quelque sorte optimal.

  • Il n'utilise pas regex, qui est difficile à maintenir
  • Il n'utilise pas de nouvelles fonctionnalités de JavaScript
  • Il n'utilise pas plusieurs invocations .split () .join () qui nécessitent plus de mémoire informatique

Juste du code pur:

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

Vous pouvez voir le code s'exécuter dans la cour de récréation: https://codeguppy.com/code.html?IJI0E4OGnkyTZnoszAzf

codeguppy
la source
0

Je ne connais pas les performances de RegEx, mais voici une autre alternative pour RegEx qui exploite HashSet natif et fonctionne à la place en complexité 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
la source
11
Ouais, que diriez-vous de tester quelque chose que vous écrivez? jsperf.com/slice-vs-custom Cela montre que votre code est en réalité 10 fois plus lent dans cet exemple. Qu'est-ce qui vous a donné l'idée que l'utilisation de 2 fois la tranche, 2 fois la concaténation, 1 fois la division, 1 décalage temporel et la mise en cache sans longueur est favorable aux performances?
Petar
J'ai mis à jour le code, maintenant il n'y a qu'une quantité minimale de tranche sans décalage, fractionnement ou etc.
Orhun Alp Oral
0

Pas le meilleur moyen mais fonctionne pour diviser avec des séparateurs / délimiteurs multiples et différents

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
la source
-3

J'utilise 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
la source
1
Cela ne fait rien avec les palindromes , juste des mots.
Nathan Tuggy