Javascript และ regex: แยกสตริงและเก็บตัวคั่น


133

ฉันมีสตริง:

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc"

และฉันต้องการแยกสตริงนี้ด้วยตัวคั่น<br />ตามด้วยอักขระพิเศษ

ในการทำเช่นนั้นฉันใช้สิ่งนี้:

string.split(/<br \/>&#?[a-zA-Z0-9]+;/g);

ฉันได้รับสิ่งที่ต้องการยกเว้นว่าฉันสูญเสียตัวคั่น นี่คือตัวอย่าง: http://jsfiddle.net/JwrZ6/1/

ฉันจะเก็บตัวคั่นไว้ได้อย่างไร


ถ้าคุณรู้จักตัวคั่นล่วงหน้าทำไมไม่ทำ ... var delim = "<br/>";?
Andreas Wong

ขอบคุณ @ SiGanteng ฉันรู้จักตัวคั่นล่วงหน้า แต่ไม่สามารถทำให้มันใช้งานได้กับตัวอย่างของฉัน ฉันต้องการให้ตัวคั่นเป็น <br /> ตามด้วยอักขระพิเศษเพราะบางครั้งฉันอาจมี <br /> ไม่ตามด้วยอักขระพิเศษและอันนี้ไม่จำเป็นต้องแยก
Miloš

2
คำถามที่ดีฉันมีกรณีที่คล้ายกันซึ่งการรู้ตัวคั่นไม่ได้ช่วยอะไร ฉันกำลังแยก "] & [" จริงๆแล้วตัวคั่นของฉันคือ "&" แต่การแยกมันไม่แม่นยำพอฉันต้องเอาวงเล็บข้างใดข้างหนึ่งมาพิจารณาการแบ่งที่เหมาะสม อย่างไรก็ตามฉันต้องการวงเล็บเหล่านั้นกลับมาในสตริงแยกของฉัน 1 ในแต่ละด้าน
PandaWood

คำตอบ:


105

ใช้Lookahead (บวก)เพื่อให้นิพจน์ทั่วไปยืนยันว่ามีอักขระพิเศษอยู่ แต่ไม่ตรงกับจริง:

string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g);

ดูการดำเนินการ:

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc";
console.log(string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g));


เมื่อฉันใช้รหัสนี้จะเพิ่ม0ที่ท้ายของแต่ละสตริง
keyboard-warrior

2
ฉันไม่พบสิ่งใดเกี่ยวกับการมองโลกในแง่บวกในลิงก์ที่คุณให้มา
Paul Chris Jones

@PaulJones เนื้อหาถูกย้ายในช่วงเวลาที่แทรกแซง ขอบคุณที่แจ้งให้ฉันทราบฉันแก้ไขลิงก์แล้ว
จอน

181

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

"1、2、3".split("、") == ["1", "2", "3"]
"1、2、3".split(/(、)/g) == ["1", "、", "2", "、", "3"]
"1、2、3".split(/(?=、)/g) == ["1", "、2", "、3"]
"1、2、3".split(/(?!、)/g) == ["1、", "2、", "3"]
"1、2、3".split(/(.*?、)/g) == ["", "1、", "", "2、", "3"]

คำเตือน:ข้อที่สี่จะใช้ได้เฉพาะกับการแยกอักขระเดี่ยวเท่านั้น ConnorsFanนำเสนอทางเลือก :

// Split a path, but keep the slashes that follow directories
var str = 'Animation/rawr/javascript.js';
var tokens = str.match(/[^\/]+\/?|\//g);

3
ฉันกำลังมองหาบางอย่างเช่นตัวอย่างที่สาม แต่จะใช้งานได้ก็ต่อเมื่อองค์ประกอบนั้นมีเพียงอักขระเดียวเท่านั้นมิฉะนั้นจะแบ่งออกเป็นแต่ละอักขระ ฉันต้องไปเส้นทางRegExp.exec ที่น่าเบื่อในที่สุด
Gordon

2
ฉันไม่เข้าใจว่าทำไมทุกคนถึงใช้ / g
Sarsaparilla

1
จะใช้ regex "1,2,3" .split (/ (?!、) / g) == ["1、", "2、", "3"] สำหรับคำเต็มได้อย่างไร ตัวอย่างเช่น "foo1, foo2, foo3"
Waltari

คุณเป็นอัจฉริยะ!. คุณพบเอกสารที่อธิบายวิธีการทำงานได้ที่ไหน คุณไม่ต้องการgจุดจบ
pery mimon

1
แปล.matchวิธีการแก้ปัญหาไม่โลภสำหรับตัวอย่างเหล่านี้: ->"11、22、33".match(/.*?、|.+$/g) ตัวปรับแต่ง["11、", "22、", "33"]หมายเหตุ/gมีความสำคัญอย่างยิ่งสำหรับการจับคู่
Beni Cherniavsky-Paskin

57

หากคุณรวมตัวคั่นไว้ในพาแรนต์มันจะเป็นส่วนหนึ่งของอาร์เรย์ที่ส่งคืน

string.split(/(<br \/>&#?[a-zA-Z0-9]+);/g);
// returns ["aaaaaa", "<br />&dagger;", "bbbb", "<br />&Dagger;", "cccc"]

ขึ้นอยู่กับส่วนที่คุณต้องการให้เปลี่ยนแปลงกลุ่มย่อยที่คุณจับคู่

string.split(/(<br \/>)&#?[a-zA-Z0-9]+;/g);
// returns ["aaaaaa", "<br />", "bbbb", "<br />", "cccc"]

คุณสามารถปรับปรุงนิพจน์โดยละเว้นกรณีของตัวอักษร string.split (/ () & #? [a-z0-9] +; / gi);

และคุณสามารถจับคู่สำหรับกลุ่มที่กำหนดไว้ล่วงหน้าเช่นนี้\dเท่ากับ[0-9]และเท่าเทียมกัน\w [a-zA-Z0-9_]ซึ่งหมายความว่านิพจน์ของคุณอาจมีลักษณะเช่นนี้

string.split(/<br \/>(&#?[a-z\d]+;)/gi);

มีดี การอ้างอิงนิพจน์ใน JavaScriptKit


4
ยิ่งไปกว่านั้นฉันไม่รู้ว่าเราสามารถเก็บเพียงบางส่วนของตัวคั่นได้ ในความเป็นจริงฉันต้องเก็บเฉพาะถ่านพิเศษฉันสามารถทำได้ด้วยสิ่งนี้: string.split (/ <br \/> (& #? [a-zA-Z0-9] +;) / g);
Miloš

1
คุณสามารถเพิ่มประสิทธิภาพการแสดงออกของคุณได้โดยไม่สนใจตัวพิมพ์ของคำ หรือจับคู่คลาสอักขระที่กำหนดไว้ล่วงหน้า ฉันจะอัปเดตคำตอบของฉัน
Torsten Walter

2
ทำไมถึงต่ำขนาดนี้ .. มันสมบูรณ์แบบและยืดหยุ่นมาก
Tofandel

2
นี่เป็นวิธีที่ง่ายที่สุดและเป็นไวยากรณ์ที่อ่านง่ายที่สุด
Timar Ivo Batis

4

ตอบได้ที่นี่ด้วย JavaScript Split Regular Expression ให้ตัวคั่น

ใช้รูปแบบ Lookahead (? = pattern) ในตัวอย่าง regex

var string = '500x500-11*90~1+1';
string = string.replace(/(?=[$-/:-?{-~!"^_`\[\]])/gi, ",");
string = string.split(",");

สิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้

[ '500x500', '-11', '*90', '~1', '+1' ]

ยังสามารถแยกโดยตรง

string = string.split(/(?=[$-/:-?{-~!"^_`\[\]])/gi);

ให้ผลลัพธ์เดียวกัน

[ '500x500', '-11', '*90', '~1', '+1' ]

ทำไมไม่แยกทันทีเหมือนในคำตอบของจอน?
Gordon

@Gordon ... :) ฉันทำได้แค่นั้น ... อัปเดตรหัส ... ไชโย
ทอด

2

ฉันได้ทำการแก้ไขคำตอบของ jichi และใส่ไว้ในฟังก์ชันที่รองรับตัวอักษรหลายตัว

String.prototype.splitAndKeep = function(separator, method='seperate'){
    var str = this;
    if(method == 'seperate'){
        str = str.split(new RegExp(`(${separator})`, 'g'));
    }else if(method == 'infront'){
        str = str.split(new RegExp(`(?=${separator})`, 'g'));
    }else if(method == 'behind'){
        str = str.split(new RegExp(`(.*?${separator})`, 'g'));
        str = str.filter(function(el){return el !== "";});
    }
    return str;
};

คำตอบของ jichi วิธีที่ 3 ใช้ไม่ได้ในฟังก์ชันนี้ดังนั้นฉันจึงใช้วิธีที่ 4 และลบช่องว่างเพื่อให้ได้ผลลัพธ์เดียวกัน

แก้ไข: วิธีที่สองซึ่งยกเว้นอาร์เรย์เพื่อแยก char1 หรือ char2

String.prototype.splitAndKeep = function(separator, method='seperate'){
    var str = this;
    function splitAndKeep(str, separator, method='seperate'){
        if(method == 'seperate'){
            str = str.split(new RegExp(`(${separator})`, 'g'));
        }else if(method == 'infront'){
            str = str.split(new RegExp(`(?=${separator})`, 'g'));
        }else if(method == 'behind'){
            str = str.split(new RegExp(`(.*?${separator})`, 'g'));
            str = str.filter(function(el){return el !== "";});
        }
        return str;
    }
    if(Array.isArray(separator)){
        var parts = splitAndKeep(str, separator[0], method);
        for(var i = 1; i < separator.length; i++){
            var partsTemp = parts;
            parts = [];
            for(var p = 0; p < partsTemp.length; p++){
                parts = parts.concat(splitAndKeep(partsTemp[p], separator[i], method));
            }
        }
        return parts;
    }else{
        return splitAndKeep(str, separator, method);
    }
};

การใช้งาน:

str = "first1-second2-third3-last";

str.splitAndKeep(["1", "2", "3"]) == ["first", "1", "-second", "2", "-third", "3", "-last"];

str.splitAndKeep("-") == ["first1", "-", "second2", "-", "third3", "-", "last"];

1

ฟังก์ชันส่วนขยายจะแยกสตริงที่มีสตริงย่อยหรือ RegEx และตัวคั่นจะถูกใส่ตามพารามิเตอร์ที่สองข้างหน้าหรือข้างหลัง

    String.prototype.splitKeep = function (splitter, ahead) {
        var self = this;
        var result = [];
        if (splitter != '') {
            var matches = [];
            // Getting mached value and its index
            var replaceName = splitter instanceof RegExp ? "replace" : "replaceAll";
            var r = self[replaceName](splitter, function (m, i, e) {
                matches.push({ value: m, index: i });
                return getSubst(m);
            });
            // Finds split substrings
            var lastIndex = 0;
            for (var i = 0; i < matches.length; i++) {
                var m = matches[i];
                var nextIndex = ahead == true ? m.index : m.index + m.value.length;
                if (nextIndex != lastIndex) {
                    var part = self.substring(lastIndex, nextIndex);
                    result.push(part);
                    lastIndex = nextIndex;
                }
            };
            if (lastIndex < self.length) {
                var part = self.substring(lastIndex, self.length);
                result.push(part);
            };
            // Substitution of matched string
            function getSubst(value) {
                var substChar = value[0] == '0' ? '1' : '0';
                var subst = '';
                for (var i = 0; i < value.length; i++) {
                    subst += substChar;
                }
                return subst;
            };
        }
        else {
            result.add(self);
        };
        return result;
    };

การทดสอบ:

    test('splitKeep', function () {
        // String
        deepEqual("1231451".splitKeep('1'), ["1", "231", "451"]);
        deepEqual("123145".splitKeep('1', true), ["123", "145"]);
        deepEqual("1231451".splitKeep('1', true), ["123", "145", "1"]);
        deepEqual("hello man how are you!".splitKeep(' '), ["hello ", "man ", "how ", "are ", "you!"]);
        deepEqual("hello man how are you!".splitKeep(' ', true), ["hello", " man", " how", " are", " you!"]);
        // Regex
        deepEqual("mhellommhellommmhello".splitKeep(/m+/g), ["m", "hellomm", "hellommm", "hello"]);
        deepEqual("mhellommhellommmhello".splitKeep(/m+/g, true), ["mhello", "mmhello", "mmmhello"]);
    });

0

ฉันใช้สิ่งนี้:

String.prototype.splitBy = function (delimiter) {
  var 
    delimiterPATTERN = '(' + delimiter + ')', 
    delimiterRE = new RegExp(delimiterPATTERN, 'g');

  return this.split(delimiterRE).reduce((chunks, item) => {
    if (item.match(delimiterRE)){
      chunks.push(item)
    } else {
      chunks[chunks.length - 1] += item
    };
    return chunks
  }, [])
}

ยกเว้นว่าคุณไม่ควรยุ่งด้วยString.prototypeดังนั้นนี่คือเวอร์ชันของฟังก์ชัน:

var splitBy = function (text, delimiter) {
  var 
    delimiterPATTERN = '(' + delimiter + ')', 
    delimiterRE = new RegExp(delimiterPATTERN, 'g');

  return text.split(delimiterRE).reduce(function(chunks, item){
    if (item.match(delimiterRE)){
      chunks.push(item)
    } else {
      chunks[chunks.length - 1] += item
    };
    return chunks
  }, [])
}

คุณสามารถทำได้:

var haystack = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc"
var needle =  '<br \/>&#?[a-zA-Z0-9]+;';
var result = splitBy(haystack , needle)
console.log( JSON.stringify( result, null, 2) )

และคุณจะจบลงด้วย:

[
  "<br />&dagger; bbbb",
  "<br />&Dagger; cccc"
]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.