Deskripsi masalah
Beberapa string kosong "" muncul saat membagi string menggunakan metode split JavaScript, terutama saat menggunakan ekspresi reguler sebagai pembatas.
Pertanyaan terkait
Ekspresi reguler JavaScript menghasilkan grup string kosong saat mengelompokkan string?
Dalam pertanyaan di atas, penanya menggunakan ekspresi reguler untuk membagi string dan menghasilkan beberapa string kosong "" dan kodenya adalah sebagai berikut:
Salinan kode adalah sebagai berikut:
'Zhang sdf empat metode asdf wengf aa33net s'.split (/([/u4e00-/u9fa5] {1})/gi);
// output ["", "zhang", "sdf", "four", "up", "", "law", "asdf", "weng", "", "", "fen", "aa33", "net", "s" s "
Jadi, apa alasan string kosong ini?
Analisis masalah
Setelah mencari di Google, saya menemukan bahwa tidak ada banyak hasil terkait. Bahkan jika ada, tidak ada banyak penjelasan terperinci. Saya secara kasar mengatakannya dan kemudian memberikan tautan ke spesifikasi ecmascript. Tampaknya jika Anda ingin mengetahui alasan sebenarnya, Anda hanya bisa menggigit peluru dan melihat norma -norma.
Standar terkait
Kemudian, menurut praktik internasional, pertama -tama pergi ke gedung standar Ecmascript Kota.
Salinan kode adalah sebagai berikut:
String.prototype.split (pemisah, batas)
Bab ini memperkenalkan langkah -langkah eksekusi metode split secara rinci. Jika Anda tertarik, Anda dapat membacanya dengan cermat langkah demi langkah. Saya hanya akan menjelaskan langkah -langkah yang terkait dengan menghasilkan string kosong di sini. Jika ada poin yang tidak pantas, semua orang dipersilakan untuk menyebutkannya.
Langkah Terkait
Langkah parsial untuk diekstrak:
Langkah terpenting dalam seluruh proses adalah siklus ke -13, dan hal -hal utama yang dilakukan siklus ini adalah sebagai berikut:
• Tentukan nilai p dan q. Nilai P dan Q adalah sama di awal setiap loop (langkah ini berada di luar loop);
• Metode Call SplitMatch (S, Q, R) untuk membagi string;
• Jalankan cabang yang berbeda sesuai dengan hasil yang dikembalikan, dan cabang utama adalah cabang;
• Cabang dibagi menjadi 8 langkah kecil untuk mengisi hasil yang dikembalikan ke array yang telah ditentukan a
• Dalam 8 langkah kecil ini, tujuan dari langkah 1 adalah untuk mengembalikan substring dari string asli, posisi awal adalah P (termasuk) dan posisi akhir adalah Q (termasuk). Catatan: Pada langkah ini, string kosong akan dihasilkan, dan saya menandainya sebagai mencegat string untuk kenyamanan mengutip di bawah ini.
• Tambahkan substring dari langkah sebelumnya ke array a
• Beberapa langkah berikutnya adalah memperbarui variabel yang relevan dan melanjutkan loop berikutnya. (Tujuan Langkah 7 adalah untuk menyimpan pengelompokan penangkapan dalam ekspresi reguler ke dalam array A, yang tidak ada hubungannya dengan generasi string kosong)
SplitMatch (S, Q, R)
Selanjutnya, kita perlu memahami apa yang dilakukan metode SplitMatch (S, Q, R). Metode ini disebutkan di bawah ini dalam spesifikasi split. Apa yang dilakukannya adalah melakukan operasi yang sesuai sesuai dengan jenis pemisah:
• Jika pembatas adalah tipe regexp, hubungi metode internal RegExp [[cocok]] untuk mencocokkan string. Jika pertandingan gagal, kembalikan kegagalan. Kalau tidak, kembalikan hasil matchResult.
• Jika pembatas adalah string, penilaian kecocokan dilakukan, kegagalan dikembalikan, dan hasil dari jenis matchResult berhasil dikembalikan.
MatchResult
Dalam langkah -langkah di atas, variabel tipe MatchResult diperkenalkan. Dengan mencari dokumen, ditemukan bahwa variabel jenis ini memiliki dua atribut endindex dan penangkapan. Nilai EndIndex adalah posisi yang cocok dengan string plus 1. Penangkapan dapat dipahami sebagai array. Ketika pembatas adalah ekspresi reguler, elemen di dalamnya adalah nilai -nilai yang ditangkap oleh grup; Ketika pembatas adalah string, itu adalah array kosong.
Berikutnya
Kita dapat melihat dari langkah -langkah di atas bahwa string split dihasilkan pada langkah mencegat string (kecuali untuk penangkapan grup ekspresi reguler). Fungsinya adalah untuk mencegat string antara awal yang ditentukan (termasuk) dan posisi akhir (termasuk), jadi kapan akan kembali ""? Ada kasus khusus di mana nilai -nilai posisi awal dan posisi akhir sama, yang hanya tebakan, karena spesifikasi tidak memberikan langkah spesifikasi untuk mencegat string.
Kita semua datang ke sini, mengapa tidak mengambil langkah maju?
Jadi, saya mencoba mencari beberapa kode sumber V8 untuk melihat apakah saya dapat menemukan metode implementasi tertentu. Saya memang menemukan kode yang relevan, tautan kode sumber
Inilah beberapa dari mereka:
Salinan kode adalah sebagai berikut:
function stringsplitjs (pemisah, batas) {
...
...
// Pembatas adalah string
if (! is_regexp (pemisah)) {
var sparator_string = to_string_inline (pemisah);
if (limit === 0) return [];
// ECMA-262 mengatakan bahwa jika pemisah tidak ditentukan, hasilnya harus
// Jadilah array ukuran 1 yang berisi seluruh string.
if (is_undefined (pemisah)) mengembalikan [subjek];
var sparator_length = petaorator_string.length;
// Pemisah adalah string kosong, yang secara langsung mengembalikan array karakter
if (petaTator_length === 0) mengembalikan %stringToArray (subjek, batas);
var result = %stringSplit (subjek, sparator_string, batas);
hasil pengembalian;
}
if (limit === 0) return [];
// Saat pembatas adalah ekspresi reguler, hubungi stringsplitonregexp
return stringPlitonRegExp (subjek, pemisah, batas, panjang);
}
// Beberapa kode dihilangkan di sini
Saya menemukan dalam kode bahwa ketika mengisi array, metode %_substring akan dipanggil untuk mencegat string. Sayangnya, saya tidak menemukan definisi yang relevan. Jika ada siswa yang menemukannya, beri tahu saya. Namun, saya menemukan bahwa metode stringSubString yang sesuai dengan metode substring di JavaScript akan memanggil metode %_substring dan mengembalikan hasilnya. Kemudian jika 'abc'.substring (1,1) mengembalikan "", itu berarti bahwa metode %_substring akan mengembalikan "" ketika posisi awal dan posisi akhir adalah sama. Anda dapat mengetahui hasilnya dengan mencobanya.
Jadi, kapan posisi mulai sama dengan posisi akhir (mis. Q === P) terjadi? Saya mengikuti langkah -langkah di atas langkah demi langkah dan akhirnya menemukan:
• Ketika String S asli cocok dengan pembatas sekali, segera setelah itu, posisi string S berikutnya juga cocok dengan pembatas. Misalnya: 'abbbc'.split (' b '),' abbbc'.split (/(b) {1}/)
• Kasus lain adalah bahwa satu atau beberapa karakter di awal string cocok dengan pemisah. Misalnya: 'abc'.split (' a '),' abc'.split (/ab/)
• Ada kasus lain di mana satu atau beberapa string di akhir string cocok dengan pembatas, dan langkah yang relevan adalah langkah 14.
Misalnya: 'abc'.split (' c '),' abc'.split (/bc/)
Selain itu, saat menggunakan ekspresi reguler sebagai pembatas, tidak terdefinisi dapat muncul dalam hasil yang dikembalikan.
Misalnya: 'abc'.split (/(d)*/)
Mari kita lihat contoh di awal. Apakah itu memenuhi situasi di atas?
Di luar topik
Ini adalah pertama kalinya saya membaca spesifikasi standar ecmascript dengan sangat hati -hati. Proses membaca memang sangat menyakitkan, tetapi setelah memahaminya, saya merasa sangat bahagia. Terima kasih atas pertanyaan ini dan pertanyaan tindak lanjutnya.
Ngomong -ngomong, ketika ekspresi reguler digunakan sebagai pemisah, pengubah global G akan diabaikan, yang juga merupakan keuntungan tambahan.