Penerangan Masalah
Sesetengah rentetan kosong "" muncul apabila menggunakan kaedah pemisahan JavaScript untuk membelah rentetan, terutamanya apabila menggunakan ungkapan biasa sebagai pembatas.
Soalan berkaitan
Ungkapan biasa JavaScript menghasilkan kumpulan rentetan kosong apabila mengumpulkan rentetan?
Dalam soalan di atas, apabila subjek menggunakan ungkapan biasa untuk memisahkan rentetan, berbilang rentetan kosong "" telah dijanakan seperti berikut:
Jadi, apakah sebab rentetan kosong ini?
Analisis Masalah
Setelah mencari di Google, saya mendapati tidak banyak hasil yang berkaitan, dan jika ada, tidak banyak penjelasan terperinci saya memberi pengenalan ringkas dan kemudian memberi pautan kepada spesifikasi ECMAScript. Rasanya kalau nak tahu sebab sebenar kena gigit dan baca peraturan.
Piawaian berkaitan
Kemudian, seterusnya, mengikut amalan antarabangsa, mari kita mulakan dengan dewan bandar standard ECMAScript.
Bab ini memperkenalkan langkah-langkah pelaksanaan kaedah split secara terperinci Jika anda berminat, anda boleh membacanya dengan teliti langkah demi langkah saya hanya akan menerangkan langkah-langkah yang berkaitan dengan menghasilkan rentetan kosong di sini. semua dialu-alukan.
Langkah berkaitan
Ekstrak beberapa langkah:
Langkah paling penting dalam keseluruhan proses ialah kitaran langkah 13, dan perkara utama kitaran ini lakukan adalah seperti berikut:
•Tentukan nilai p dan q Nilai p dan q adalah sama pada permulaan setiap gelung (langkah ini berada di luar gelung);
•Panggil kaedah SplitMatch(S, q, R) untuk membelah rentetan;
•Menurut keputusan berbeza yang dikembalikan, cawangan berbeza dilaksanakan, dan cawangan utama ialah cawangan ⅲ
•Cawangan ⅲ dibahagikan kepada 8 langkah kecil untuk mengisi hasil yang dikembalikan ke dalam tatasusunan yang telah ditetapkan A
•Dalam 8 langkah kecil ini, fungsi langkah 1 adalah untuk mengembalikan subrentetan rentetan asal Kedudukan permulaan ialah p (inklusif) dan kedudukan akhir ialah q (tidak termasuk). dihasilkan, yang saya tandai sebagai rentetan terpotong untuk rujukan mudah di bawah.
•Tambahkan subrentetan daripada langkah sebelumnya ke tatasusunan A
•Beberapa langkah seterusnya ialah mengemas kini pembolehubah yang berkaitan dan meneruskan kitaran seterusnya. (Fungsi langkah 7 adalah untuk menyimpan kumpulan tangkapan dalam ungkapan biasa ke dalam tatasusunan A, dan tiada kaitan dengan menjana rentetan kosong)
SplitMatch(S, q, R)
Seterusnya, kita perlu memahami apa yang dilakukan oleh kaedah SplitMatch(S, q, R). Kaedah ini disebut lebih jauh di bawah dalam spesifikasi split. Perkara utama yang dilakukannya ialah melakukan operasi yang sepadan mengikut jenis pemisah:
•Jika pemisah ialah rentetan, padanan dinilai, kegagalan dikembalikan dan hasil jenis MatchResult dikembalikan dengan jayanya.
Keputusan Perlawanan
Langkah di atas memperkenalkan satu lagi pembolehubah jenis MatchResult. Dengan menyemak dokumentasi, kami mendapati bahawa pembolehubah jenis ini mempunyai dua atribut, endIndex dan tangkapan Nilai endIndex ialah kedudukan padanan rentetan ditambah 1. Tangkapan boleh difahami sebagai tatasusunan Apabila pembatas ialah ungkapan biasa, elemen di dalamnya adalah nilai yang ditangkap oleh kumpulan; apabila pembatas ialah rentetan, ia adalah tatasusunan kosong.
Seterusnya
Kita boleh lihat daripada langkah-langkah di atas bahawa rentetan pecahan dijana dalam langkah memintas rentetan (kecuali tangkapan kumpulan ungkapan biasa). Fungsinya adalah untuk memintas rentetan antara kedudukan mula (inklusif) dan akhir yang ditentukan (tidak termasuk), jadi bilakah ia akan mengembalikan ""? Terdapat kes khas di mana nilai kedudukan mula dan kedudukan akhir adalah sama. Ini hanya tekaan, kerana spesifikasi tidak memberikan langkah standard untuk memintas rentetan.
Kita sudah sampai sejauh ini, kenapa tidak melangkah setapak lagi ke hadapan?
Jadi, saya cuba mencari beberapa kod sumber V8 untuk melihat sama ada saya boleh mencari kaedah pelaksanaan tertentu. Saya telah menemui kod yang berkaitan, pautan kod sumber
Berikut adalah petikan daripada salah seorang daripada mereka:
jika (had === 0) kembalikan [];
// ECMA-262 mengatakan bahawa jika pemisah tidak ditentukan, hasilnya seharusnya
// menjadi tatasusunan saiz 1 yang mengandungi keseluruhan rentetan.
Jika (IS_UNDEFINED(separator)) kembalikan [subjek];
var separator_length = separator_string.length;
//Pembatas ialah rentetan kosong, dan tatasusunan aksara dikembalikan terus
Jika (separator_length === 0) kembalikan %StringToArray(subjek, had);
hasil var = %StringSplit(subjek, separator_string, had);
pulangkan hasil;
}
jika (had === 0) kembalikan [];
// Apabila pemisah ialah ungkapan biasa, panggil StringSplitOnRegExp
Kembalikan StringSplitOnRegExp(subjek, pemisah, had, panjang);
}
//Tinggalkan beberapa kod di sini
Saya dapati dalam kod bahawa kaedah %_SubString dipanggil untuk memintas rentetan apabila mengisi tatasusunan Malangnya, saya tidak menemui definisi yang berkaitan Jika anda menemuinya, sila beritahu saya. Walau bagaimanapun, saya mendapati bahawa kaedah StringSubstring yang sepadan dengan kaedah substring dalam JavaScript akan memanggil kaedah %_SubString dan mengembalikan hasilnya. Kemudian jika 'abc'.substring(1,1) mengembalikan "", ini bermakna kaedah %_SubString akan mengembalikan "" apabila kedudukan mula dan kedudukan akhir adalah sama Anda akan tahu hasilnya selepas mencubanya.
Jadi, bilakah kedudukan permulaan akan bersamaan dengan kedudukan penamat (iaitu q === p)? Saya menganalisis langkah demi langkah mengikut langkah di atas, dan akhirnya menemui:
•Selepas rentetan asal S padan dengan pembatas sekali, kedudukan rentetan S seterusnya juga sepadan dengan pembatas. Seperti: 'abbbc'.split('b'), 'abbbc'.split(/(b){1}/)
•Situasi lain ialah apabila satu atau beberapa aksara pada permulaan rentetan sepadan dengan pembatas. Seperti: 'abc'.split('a'), 'abc'.split(/ab/)
•Terdapat juga kes di mana satu atau beberapa rentetan pada penghujung rentetan sepadan dengan pembatas, dan langkah yang berkaitan ialah langkah 14.
Seperti: 'abc'.split('c'), 'abc'.split(/bc/)
Selain itu, apabila menggunakan ungkapan biasa sebagai pembatas, undefined mungkin muncul dalam hasil yang dikembalikan.
Seperti: 'abc'.split(/(d)*/)
Kembali dan lihat contoh pada permulaan adakah ia memenuhi syarat di atas?
Penyimpangan
Ini adalah kali pertama saya membaca spesifikasi standard ECMAScript dengan begitu teliti Proses membacanya memang menyakitkan, tetapi setelah memahaminya, saya berasa sangat gembira. Terima kasih juga kepada penyoal kerana mengemukakan soalan ini dan membuat susulan.
Dengan cara ini, apabila ungkapan biasa digunakan sebagai pembatas, pengubah suai global g akan diabaikan, yang merupakan keuntungan tambahan.