ฉันจะแยกสตริงที่มีตัวคั่นหลายตัวใน javascript ได้อย่างไร


504

ฉันจะแยกสตริงที่มีตัวคั่นหลายตัวใน JavaScript ได้อย่างไร ฉันพยายามแยกทั้งคอมม่าและช่องว่าง แต่ AFAIK ฟังก์ชันแยกของ JS รองรับตัวคั่นเดียวเท่านั้น


3
ฉันมีปัญหานี้พยายามแบ่งเส้นทางไฟล์ที่สร้างขึ้นด้วย nodejs ภายใต้ windows มีเครื่องหมาย "/" และเครื่องหมาย "\" ย้อนกลับอยู่ในเส้นทางเดียวกันในบางครั้ง
Fuhrmanator

คำตอบ:


707

ผ่าน regexp เป็นพารามิเตอร์:

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 การใช้จาวาสคริปต์ของ Mozilla ใน Java: mozilla.org/rhino (... หรือ "sudo apt-get install rhino")
Aaron Maenpaa

ขอบคุณ คำถามที่เกี่ยวข้องกับสิ่งนี้สิ่งที่ฉันต้องทำคือได้รับองค์ประกอบสุดท้ายของอาร์เรย์แยก หากไม่มีอาเรย์ก็ควรส่งคืนสตริงขอบคุณ

2
มีวิธีใดที่จะหลีกเลี่ยงการลบตัวคั่นเมื่อแยกด้วยนิพจน์ทั่วไปหรือไม่?
Anderson Green

วิธีการแยกทั้งสตริง "hello world" รวมถึงอักขระอื่น (หรือ regex อื่น ๆ ) เช่นสัญลักษณ์ไปป์ ความพยายามที่หลากหลาย(hello world)|\|ยังไม่ได้ผล ความคิดใด ๆ
บ๊องเกี่ยวกับ natty

183

คุณสามารถส่งผ่าน regex ลงผู้ประกอบการแยกของ Javascript ตัวอย่างเช่น:

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

หรือหากคุณต้องการให้ตัวคั่นหลายตัวรวมกันทำหน้าที่เป็นตัวเดียวเท่านั้น:

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

(คุณต้องใช้การไม่จับภาพ (? :) parens เพราะมิฉะนั้นมันจะกลับมาเป็นผลหรือคุณอาจฉลาดเหมือนแอรอนและใช้คลาสตัวละคร)

(ตัวอย่างทดสอบใน Safari + FF)


3
หากคุณต้องการอักขระหลายตัวเพื่อทำหน้าที่เป็นตัวเดียวดังเช่นพูด "one; #two; #new jersey" คุณสามารถส่งสตริง "; #" ไปยังฟังก์ชันแยกได้ "one; #two; #new jersey" .split ("; #") [2] === "นิวเจอร์ซีย์"
Oskar Austegard

วิธีนี้ใช้งานได้ดีกว่าคลาสอักขระหากคุณต้องการแยกอักขระมากกว่าหนึ่งตัว แยกพวกเขาออกตาม|ที่ Jesse แสดง
devios1

ฉันสงสัยว่ามีวิธีหลีกเลี่ยงการลบตัวคั่นเมื่อแยกสตริงด้วยนิพจน์ทั่วไปหรือไม่: ตัวอย่างนี้จะลบตัวคั่น แต่ฉันหวังว่าเป็นไปได้ที่จะแยกสตริงโดยไม่ลบออก
Anderson Green

1
@AndersonGreen มันขึ้นอยู่กับสิ่งที่คุณต้องการ; ในกรณีนี้มีตัวคั่นหลายตัวคุณต้องการเก็บไว้ทั้งหมดหรือไม่ ในฐานะรายการแยกต่างหาก เข้าร่วมรายการก่อนหน้าหรือไม่ รายการต่อไป? ดูเหมือนไม่ชัดเจนสำหรับฉัน คุณอาจต้องการตั้งคำถามใหม่ด้วยตัวอย่างของสิ่งที่คุณกำลังมองหา
Jesse Rusak

@JesseRusak ฉันหมายถึงการรักษาตัวคั่นทั้งหมดเป็นรายการแยกต่างหากเพื่อให้สตริงสามารถโทเค็นโดยใช้รายการตัวคั่น
Anderson Green

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ฟังก์ชั่นหากใช้วิธีการนี้กับด้านล่างเพียงแค่หุ้มมัน :) นอกจากนี้ยังมีข้อสังเกตว่าบางคนขมวดคิ้วต่อการขยายบิวด์อิน (อย่างที่หลายคนทำผิดและความขัดแย้งเกิดขึ้น) ดังนั้นหากมีข้อสงสัยให้พูดคุยกับคนที่อาวุโสกว่าก่อนที่จะใช้สิ่งนี้หรือถาม 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
    };

การใช้งาน:

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++)?
tic

ฉันพลาดการเพิ่มประสิทธิภาพแล้วคุณถูกต้องที่เราสามารถเริ่มต้นtokens[1]เพื่อบันทึกการวนซ้ำหนึ่งครั้งtokens[0] == tempcharและเราแยกtempcharหลังจากการวนซ้ำtokensเพื่อจบการทำงาน ฉันจะอัปเดตคำตอบตามนั้นขอบคุณ @tic :)
Brian

20

ให้ง่าย: (เพิ่ม "[] +" ใน RegEx ของคุณหมายถึง "1 หรือมากกว่า")

ซึ่งหมายความว่า "+" และ "{1,}" เหมือนกัน

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

2
เพิ่ม "+" ที่ท้ายหมายถึง 1 หรือมากกว่า
Asher

6
ฉันจะบอกว่านี่เป็นเรื่องเล็กน้อยไม่ใช่เรื่องง่าย
Darryl Hebbes

สำหรับเครื่องหมาย + และ - :-D แต่ยัง \ s แทนอักขระถ่านว่าง: var words = text.split (/ [\ s.:;?!~,`"&&(()> \ + \ - [] \ r \ n / \] + /);
Didier68

12

วิธีการหากิน:

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

3
สิ่งนี้ผิดเพราะ. แทนที่ () ไม่ได้แทนที่องค์ประกอบทั้งหมด:/

1
คุณสามารถเปลี่ยน'('สำหรับ/(/gที่จะเปลี่ยนทุก(องค์ประกอบ - gเป็นโลกธงนิพจน์ทั่วไป - ดังนั้นจึงค้นหาที่เกิดขึ้นทั้งหมด(ไม่ได้คนแรก
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

@ rerianor ของ @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

ผมพบว่าหนึ่งในเหตุผลหลักที่ฉันต้องการนี้คือการแยกเส้นทางแฟ้มทั้งบนและ/ \มันเป็นบิตของ regex ที่ซับซ้อนดังนั้นฉันจะโพสต์ไว้ที่นี่เพื่อการอ้างอิง:

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 solution (นั่นเป็นสิ่งที่น่าสนใจสำหรับฉัน!) ฉันได้ปรับเปลี่ยนเล็กน้อยเพื่อให้เป็นแบบทั่วไปและใช้ซ้ำได้มากขึ้น:

/**
 * 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 และเป็นวิธีที่เหมาะสมที่สุด

  • ไม่ใช้ regex ซึ่งยากต่อการบำรุงรักษา
  • ไม่ใช้คุณสมบัติใหม่ของ 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 (สูงสุด (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 ครั้งและไม่มีแคชระยะเวลาเป็นมิตร?
Petar

ฉันอัปเดตรหัสแล้วตอนนี้มีจำนวนชิ้นขั้นต่ำเพียงอย่างเดียวโดยไม่มีการเปลี่ยนแปลงแยกหรืออื่น ๆ
Orhun Alp Oral

0

ไม่ใช่วิธีที่ดีที่สุด แต่ทำงานเพื่อแยกด้วยตัวคั่น / ตัวคั่นหลายตัว

HTML

<button onclick="myFunction()">Split with Multiple and Different seperators/delimiters</button>
<p id="demo"></p>

จาวาสคริปต์

<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
สิ่งนี้ไม่ได้ทำอะไรเลยกับpalindromesแค่พูด
นาธาน Tuggy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.