Як розділити рядок на кілька роздільників у JavaScript?


504

Як розділити рядок на кілька роздільників у JavaScript? Я намагаюся розділити на коми і пробіли, але, AFAIK, функція розбиття JS підтримує лише один роздільник.


3
У мене була ця проблема, намагаючись розділити шляхи до файлів, побудовані за допомогою nodejs під Windows. Іноді в одному і тому ж шляху траплялися косої смуги "/" та "назад".
Фурманатор

Відповіді:


707

Передати в регулярному вираженні як параметр:

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

Відредаговано, щоб додати:

Останній елемент можна отримати, вибравши довжину масиву мінус 1:

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

... і якщо візерунок не відповідає:

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

1
Що ви використовуєте для своєї js> консолі?
серцевина

4
rhino, реалізація JavaScript на Java на Java: mozilla.org/rhino (... або "sudo apt-get install rhino").
Аарон Маенпаа

Дякую. Ще одне питання, пов’язане з цим, що мені потрібно зробити - це отримати останній елемент розбитого масиву. якщо немає масиву, він повинен повернути рядок thx

2
Чи є якийсь спосіб уникнути видалення роздільників при розщепленні регулярним виразом?
Андерсон Грін

Як розділити як на рядок "привіт світ", так і на інший символ (або інший вираз), як символ труби? Випробувані варіанти (hello world)|\|яких ще не дуже спрацювали. Будь-які ідеї?
горіх про natty

183

Ви можете передати регулярний вираз у розділений оператор Javascript . Наприклад:

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

Або, якщо ви хочете дозволити безлічі сепараторів разом діяти лише як один:

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

(Ви повинні використовувати нехоплені (? :) парони, тому що в іншому випадку вони повертаються в результат. Або ви можете бути розумними, як Аарон і використовувати клас символів.)

(Приклади, перевірені в Safari + FF)


3
Якщо вам потрібно кілька символів, щоб діяти як один, скажімо, "one; #two; # new jersey", ви можете просто передати рядок "#" у роздільну функцію. "one; #two; # new jersey" .split ("; #") [2] === "new jersey"
Oskar Austegard

Цей метод працює краще, ніж класи символів, якщо вам потрібно розділити на кілька символів. Відокремте їх, |як показує Джессі.
devios1

Цікаво, чи є спосіб уникнути видалення роздільників при розділенні рядка звичайним виразом: цей приклад видаляє роздільники, але, сподіваюся, можна розділити рядок, не видаляючи їх.
Андерсон Грін,

1
@AndersonGreen Це залежить від того, що саме ти хочеш; в цьому випадку є кілька роздільників, тому ви хочете зберегти їх усі? Як окремий предмет? Приєднався до попереднього пункту? Наступний елемент? Мені це здається незрозумілим. Можливо, ви захочете поставити нове запитання з кількома прикладами того, що шукаєте.
Джессі Русак

@JesseRusak Я мав на увазі зберігати всі роздільники як окремі елементи, щоб строк міг бути токенізований за допомогою списку роздільників.
Андерсон Грін

55

Ще один простий, але ефективний метод - використовувати split + join неодноразово.

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

По суті, розбиття з подальшим з'єднанням - це як глобальна заміна, тому це замінює кожен роздільник комою, після того, як всі замінені, він робить остаточний розділ на кому

Результатом наведеного виразу є:

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

Розширюючи це, ви також можете розмістити його у функції:

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

Використання:

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

Якщо ви багато використовуєте цю функціональність, можливо, варто навіть розглянути обгортання String.prototype.split для зручності (я думаю, що моя функція досить безпечна - єдиний розгляд - це додаткові накладні витрати умовних умов (мінор) та той факт, що їй не вистачає реалізації граничного аргументу якщо передано масив).

Обов’язково включіть цю splitMultiфункцію, якщо використання цього підходу до наведеного нижче просто завершить її :). Також варто відзначити, що деякі люди нахмурилися на розширення вбудованих модулів (оскільки багато людей роблять це неправильно і можуть виникати конфлікти), тому якщо у вас виникли сумніви, перед тим, як скористатися цим, або запитайте про це :)

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

Використання:

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

Насолоджуйтесь!


3
Чому ви пишете, for(var i = 0; i < tokens.length; i++)а ні for(var i = 1; i < tokens.length; i++)?
тик

Я пропустив цю оптимізацію, ти маєш рацію, ми можемо почати, tokens[1]щоб зберегти одну ітерацію, tokens[0] == tempcharі ми розділилися tempcharпісля ітерації, tokensщоб закінчити. Відповідно оновлю відповідь завдяки @tic :).
Брайан

20

Нехай це буде просто: (додати "[] +" до вашого RegEx означає "1 або більше")

Це означає, що "+" і "{1,}" однакові.

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

2
додати "+" в кінці означає 1 або більше
Asher

6
Я б сказав, що це мінімально, а не просто
Дарріл Геббс

Для значень + і - :-D, але також \ s замість порожнього знаку: var words = text.split (/ [\ \::?!~,`"&|()<>{}\= \ + \ - [] \ r \ n / \] + /);
Дідьє68,

12

Хитрий метод:

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

3
це неправильно, оскільки .replace () замінює не всі елементи:/

1
Ви можете змінити '('для того /(/gщоб замінити всі (елементи - gце глобальний прапор для RegExp - так це пошук всіх входжень (не перший один
codename-

7

Для тих із вас, хто бажає більшої настройки у своїй функції розщеплення, я написав рекурсивний алгоритм, який розбиває заданий рядок зі списком символів, на який слід розділити. Я писав це ще до того, як побачив вищезгаданий пост. Я сподіваюся, що це допоможе розчарованим програмістам.

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

Приклад вище повертає: ["people", "and", "other", "things"]

Примітка: flattenфункція була взята з коду Rosetta


6

Ви можете просто зібрати всі символи, які ви хочете використовувати як роздільники, поодиноко або спільно, у звичайний вираз і передати їх до функції розділення. Наприклад, ви можете написати:

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

А вихід буде:

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

3

Можливо, вам слід зробити якусь заміну рядків, щоб перетворити один роздільник на інший, щоб у вас був лише один роздільник, з яким ви зможете розібратися у своєму розділі.


3

Привіт, наприклад, якщо ви розділили і замінили в String 07:05:45 PM

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

Результат

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

3

Ось новий спосіб досягти того ж у 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));

Зверніть увагу на цю функцію:

  • Жоден Regex не бере участь
  • Повертає розділене значення в тому ж порядку, як і в source

Результатом наведеного вище коду було б:

введіть тут опис зображення


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

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

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

це поверне рядок без спеціального символу.


2

Мій рефактор відповіді @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

Я вважаю, що одна з головних причин, що мені це потрібно, - це розділити шляхи до файлів на обох /і \. Це трохи хитрий вираз, тому я опублікую його тут для довідки:

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

1

Я думаю, що простіше, якщо ви вкажете, що ви хочете залишити, а не те, що ви хочете видалити.

Як якщо ви хочете мати лише англійські слова, ви можете використовувати щось подібне:

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

Приклади (запустіть фрагмент):

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

Починаючи з рішення @ stephen-sweriduk (це було мені цікавіше!), Я трохи змінив його, щоб зробити більш загальним і багаторазовим:

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

}

і потім

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

що повертається як оригінал:

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

1

Простий спосіб зробити це - обробити кожен символ рядка з кожним роздільником і створити масив розбиття:

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

Використання: splix(string, delimiters...)

Приклад: splix("1.23--4", ".", "--")

Повернення: ["1", "23", "4"]


1

Я забезпечу класичну реалізацію такої функції. Код працює майже у всіх версіях JavaScript і є якимось оптимальним.

  • Він не використовує регулярний вираз, який важко підтримувати
  • Він не використовує нові функції JavaScript
  • Він не використовує кілька викликів .split () .join (), для яких потрібно більше пам'яті комп'ютера

Просто чистий код:

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

Ви можете побачити код, який працює на дитячому майданчику: https://codeguppy.com/code.html?IJI0E4OGnkyTZnoszAzf


0

Я не знаю працездатності RegEx, але ось інша альтернатива для RegEx використовує нативний HashSet і працює замість складної 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
Так, а як ти насправді тестуєш те, що пишеш? jsperf.com/slice-vs-custom Це показує, що ваш код насправді в цьому прикладі в 10 разів повільніше. Що дало вам уявлення про те, що використання 2-красного зрізу, 2-разового континуту, 1-разового розділення, 1-часової зміни та жодного кешування довжини не є ефективними?
Петро

Я оновив код, тепер є лише мінімальна кількість зрізу без зсуву, розбиття і т. Д.
Orhun Alp Oral

0

Не найкращий спосіб, але працює з розділенням декількох і різних сепараторів / роздільників

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

Я використовую 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
Це не робить нічого з паліндром , а лише слова.
Натан Туггі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.