Javascript dan regex: pisahkan string dan pertahankan pemisah

132

Saya memiliki string:

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

Dan saya ingin membagi string ini dengan pembatas yang <br />diikuti dengan karakter khusus.

Untuk melakukan itu, saya menggunakan ini:

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

Saya mendapatkan apa yang saya butuhkan, kecuali bahwa saya kehilangan pembatas. Ini contohnya: http://jsfiddle.net/JwrZ6/1/

Bagaimana cara mempertahankan pembatas?

Miloš
sumber
Jika Anda mengetahui pembatasnya terlebih dahulu, mengapa tidak dilakukan saja ... var delim = "<br/>";?
Andreas Wong
Terima kasih @SiGanteng, saya tahu pembatas sebelumnya tetapi saya tidak dapat membuatnya berfungsi untuk contoh saya. Saya perlu menjaga pembatas agar <br /> diikuti oleh karakter khusus karena terkadang saya dapat memiliki <br /> tidak diikuti oleh karakter khusus dan yang ini tidak harus dipisahkan.
Miloš
2
Pertanyaan bagus, saya memiliki kasus serupa di mana mengetahui pembatas tidak membantu. Saya membagi "] & [". Jadi sebenarnya pembatas saya adalah "&" tetapi pemisahan itu tidak cukup tepat, saya perlu mendapatkan tanda kurung di kedua sisi untuk menentukan pembagian yang tepat. Namun, saya membutuhkan tanda kurung itu kembali di string split saya. 1 di setiap sisi.
PandaWood

Jawaban:

104

Menggunakan lookahead (positif) sehingga ekspresi reguler menegaskan bahwa karakter khusus ada, tetapi tidak benar-benar cocok:

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

Lihat aksinya:

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

Jon
sumber
Ketika saya menggunakan kode ini, ia menambahkan a 0di akhir setiap string
keyboard-warrior
2
Saya tidak dapat menemukan apa pun tentang orang yang berpenampilan positif di tautan yang Anda berikan.
Paul Chris Jones
@PaulJones konten dipindahkan dalam waktu sela. Terima kasih telah memberi tahu saya, saya telah memperbaiki tautannya.
Jon
180

Saya mengalami masalah yang serupa tetapi sedikit berbeda. Bagaimanapun, berikut adalah contoh dari tiga skenario berbeda untuk menyimpan deliminator.

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

Peringatan: Yang keempat hanya akan berfungsi untuk memisahkan karakter tunggal. ConnorsFan menghadirkan alternatif :

// Split a path, but keep the slashes that follow directories
var str = 'Animation/rawr/javascript.js';
var tokens = str.match(/[^\/]+\/?|\//g);
jichi
sumber
3
Saya mencari sesuatu seperti contoh ketiga, tetapi ini hanya berfungsi jika elemennya hanya satu karakter - itu akan terpecah menjadi karakter individu jika tidak. Saya harus melalui rute RegExp.exec yang membosankan pada akhirnya.
Gordon
2
Saya tidak mengerti mengapa semua orang menggunakan / g
Sarsaparilla
1
Bagaimana menggunakan regex "1、2、3" .split (/ (?! 、) / G) == ["1 、", "2 、", "3"] ini untuk kata lengkap? Misalnya "foo1, foo2, foo3,"
Waltari
Kamu jenius!. di mana Anda menemukan dokumentasi yang menjelaskan cara kerjanya? Anda tidak membutuhkan gakhir
pery mimon
1
Terjemahan .matchsolusi tidak serakah untuk contoh berikut: "11、22、33".match(/.*?、|.+$/g)-> ["11、", "22、", "33"]. /gPengubah catatan sangat penting untuk pertandingan.
Beni Cherniavsky-Paskin
57

Jika Anda membungkus pembatas dalam tanda kurung, itu akan menjadi bagian dari larik yang dikembalikan.

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

Bergantung pada bagian mana Anda ingin tetap mengubah subgrup mana yang Anda cocokkan

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

Anda dapat memperbaiki ekspresi dengan mengabaikan kasus huruf string.split (/ () & #? [A-z0-9] +; / gi);

Dan Anda dapat mencocokkan untuk grup yang ditentukan sebelumnya seperti ini: \dsama dengan [0-9]dan \wsama [a-zA-Z0-9_]. Artinya ekspresi Anda bisa terlihat seperti ini.

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

Ada Referensi Ekspresi Reguler yang bagus di JavaScriptKit .

Torsten Walter
sumber
4
Bahkan lebih baik lagi, saya tidak tahu bahwa kita hanya dapat menyimpan sebagian dari pembatas. Sebenarnya saya hanya perlu menyimpan karakter khusus, saya dapat melakukannya dengan ini: string.split (/ <br \/> (& #? [A-zA-Z0-9] +;) / g);
Miloš
1
Anda dapat mengoptimalkan ekspresi Anda dengan mengabaikan kasus kata. Atau cocok untuk kelas karakter yang telah ditentukan sebelumnya. Saya akan memperbarui jawaban saya.
Torsten Walter
2
Mengapa ini sangat rendah .. Ini sempurna dan sangat fleksibel
Tofandel
2
Ini tentunya cara termudah, dan sintaks yang paling mudah dibaca.
Timar Ivo Batis
4

jawabnya disini juga JavaScript Split Regular Expression pertahankan pembatasnya

gunakan pola lookahead (? = pattern) pada contoh regex

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

ini akan memberi Anda hasil sebagai berikut.

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

Bisa juga langsung dibelah

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

memberikan hasil yang sama

[ '500x500', '-11', '*90', '~1', '+1' ]
Menggoreng
sumber
Mengapa tidak langsung saja berpisah, seperti jawaban Jon yang diterima?
Gordon
@Gordon ... :) Saya hanya bisa melakukan itu ... memperbarui kodenya ... Cheers
Fry
2

Saya membuat modifikasi pada jawaban jichi, dan memasukkannya ke dalam fungsi yang juga mendukung banyak huruf.

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

jawaban jichi Metode ke-3 tidak akan berfungsi dalam fungsi ini, jadi saya mengambil metode ke-4, dan menghapus ruang kosong untuk mendapatkan hasil yang sama.

edit: metode kedua yang mengecualikan array untuk memisahkan char1 atau 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);
    }
};

pemakaian:

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

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

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

Fungsi ekstensi membagi string dengan substring atau RegEx dan pembatas diletakkan sesuai dengan parameter kedua di depan atau di belakang.

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

Ujian:

    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"]);
    });
Berezh
sumber
0

Saya telah menggunakan ini:

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
  }, [])
}

Kecuali Anda tidak boleh main-main String.prototype, jadi inilah versi fungsinya:

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
  }, [])
}

Jadi Anda bisa melakukan:

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

Dan Anda akan mendapatkan:

[
  "<br />&dagger; bbbb",
  "<br />&Dagger; cccc"
]
vasilevich.dll
sumber