คำอธิบายปัญหา
สตริงว่างเปล่า "" บางส่วนจะปรากฏขึ้นเมื่อแยกสตริงโดยใช้วิธีการแยกของ JavaScript โดยเฉพาะอย่างยิ่งเมื่อใช้นิพจน์ทั่วไปเป็นตัวคั่น
คำถามที่เกี่ยวข้อง
นิพจน์ทั่วไปของ JavaScript สร้างกลุ่มสตริงว่างเมื่อจัดกลุ่มสตริง?
ในคำถามข้างต้นผู้ถามใช้นิพจน์ทั่วไปเพื่อแยกสตริงและสร้างสตริงว่างเปล่าหลายสาย "" และรหัสมีดังนี้:
การคัดลอกรหัสมีดังนี้:
'Zhang SDF สี่วิธี ASDF WENGF AA33NET S'.SPLIT (/([/U4E00-/U9FA5] {1})/GI);
// output ["", "Zhang", "SDF", "Four", "Up", "", "Law", "ASDF", "Weng", "", "", "Fen", "AA33", "Net", "S"
ดังนั้นอะไรคือเหตุผลสำหรับสตริงที่ว่างเปล่าเหล่านี้?
การวิเคราะห์ปัญหา
หลังจากค้นหาบน Google ฉันพบว่ามีผลลัพธ์ที่เกี่ยวข้องไม่มากนัก แม้ว่าจะมี แต่ก็มีคำอธิบายรายละเอียดไม่มากนัก ฉันพูดอย่างคร่าวๆแล้วให้ลิงก์ไปยังข้อกำหนด ECMASCRIPT ดูเหมือนว่าถ้าคุณต้องการทราบเหตุผลที่แท้จริงคุณสามารถกัดกระสุนและดูบรรทัดฐานได้
มาตรฐานที่เกี่ยวข้อง
จากนั้นตามการปฏิบัติระหว่างประเทศก่อนอื่นไปที่อาคารเมืองมาตรฐานของ Ecmascript
การคัดลอกรหัสมีดังนี้:
string.prototype.split (ตัวคั่น, ขีด จำกัด )
บทนี้แนะนำขั้นตอนการดำเนินการของวิธีการแยกโดยละเอียด หากคุณสนใจคุณสามารถอ่านได้ทีละขั้นตอน ฉันจะอธิบายขั้นตอนที่เกี่ยวข้องกับการสร้างสตริงที่ว่างเปล่าที่นี่เท่านั้น หากมีคะแนนที่ไม่เหมาะสมทุกคนยินดีที่จะพูดถึงพวกเขา
ขั้นตอนที่เกี่ยวข้อง
ขั้นตอนบางส่วนในการแยก:
ขั้นตอนที่สำคัญที่สุดในกระบวนการทั้งหมดคือรอบที่ 13 และสิ่งสำคัญรอบนี้มีดังนี้:
•กำหนดค่าของ p และ q ค่าของ P และ Q จะเหมือนกันที่จุดเริ่มต้นของแต่ละลูป (ขั้นตอนนี้อยู่นอกลูป);
•วิธีการ Call SplitMatch (s, q, r) เพื่อแยกสตริง;
•ดำเนินการสาขาที่แตกต่างกันตามผลลัพธ์ที่ส่งคืนและสาขาหลักคือสาขา
•สาขาแบ่งออกเป็น 8 ขั้นตอนเล็ก ๆ เพื่อเติมผลลัพธ์ที่ส่งคืนในอาร์เรย์ที่กำหนดไว้ล่วงหน้า
•ในขั้นตอนเล็ก ๆ 8 ขั้นตอนนี้วัตถุประสงค์ของขั้นตอนที่ 1 คือการส่งคืนสตริงย่อยของสตริงต้นฉบับตำแหน่งเริ่มต้นคือ P (รวม) และตำแหน่งสุดท้ายคือ Q (รวม) หมายเหตุ: ในขั้นตอนนี้จะมีการสร้างสตริงว่างเปล่าและฉันทำเครื่องหมายว่าเป็นการสกัดกั้นสตริงเพื่อความสะดวกในการอ้างถึงด้านล่าง
•เพิ่มสตริงย่อยจากขั้นตอนก่อนหน้าไปยังอาร์เรย์ก
•ขั้นตอนต่อไปคือการอัปเดตตัวแปรที่เกี่ยวข้องและดำเนินการวนซ้ำต่อไป (วัตถุประสงค์ของขั้นตอนที่ 7 คือการบันทึกการจัดกลุ่มการจับภาพในนิพจน์ทั่วไปลงในอาร์เรย์ A ซึ่งไม่มีส่วนเกี่ยวข้องกับการสร้างสตริงว่าง)
SplitMatch (S, Q, R)
ต่อไปเราต้องเข้าใจว่าวิธี Splitmatch (s, q, r) ทำอะไร วิธีนี้ถูกกล่าวถึงด้านล่างในข้อกำหนดการแยก สิ่งที่ส่วนใหญ่ทำคือการดำเนินการที่สอดคล้องกันตามประเภทของตัวคั่น:
•หากตัวคั่นเป็นประเภท regexp ให้โทรหาวิธีการภายในของ Regexp [[จับคู่]] เพื่อให้ตรงกับสตริง หากการแข่งขันล้มเหลวให้ส่งคืนความล้มเหลว มิฉะนั้นให้ส่งคืนผลลัพธ์ Matchresult
•หากตัวคั่นเป็นสตริงการตัดสินการจับคู่จะถูกส่งคืนความล้มเหลวจะถูกส่งคืนและเป็นผลมาจากประเภทการจับคู่จะถูกส่งคืนสำเร็จ
การจับคู่
ในขั้นตอนข้างต้นมีการแนะนำตัวแปรประเภท Matchresult จากการค้นหาเอกสารพบว่าตัวแปรประเภทนี้มีสองแอตทริบิวต์ endindex และการจับภาพ ค่าของ endindex คือตำแหน่งที่ตรงกับสตริงบวก 1 การจับสามารถเข้าใจได้ว่าเป็นอาร์เรย์ เมื่อตัวคั่นเป็นนิพจน์ทั่วไปองค์ประกอบภายในจะเป็นค่าที่จับโดยกลุ่ม; เมื่อตัวคั่นเป็นสตริงมันเป็นอาร์เรย์ที่ว่างเปล่า
ต่อไป
เราสามารถเห็นได้จากขั้นตอนข้างต้นว่าสตริงแยกถูกสร้างขึ้นในขั้นตอนของการสกัดกั้นสตริง (ยกเว้นการจับกลุ่มของนิพจน์ปกติ) ฟังก์ชั่นของมันคือการสกัดกั้นสตริงระหว่างการเริ่มต้นที่ระบุ (รวม) และตำแหน่งสิ้นสุด (รวม) ดังนั้นเมื่อไหร่จะกลับ ""? มีกรณีพิเศษที่ค่าของตำแหน่งเริ่มต้นและตำแหน่งสิ้นสุดเท่ากันซึ่งเป็นเพียงการคาดเดาเนื่องจากข้อกำหนดไม่ได้ให้ขั้นตอนข้อกำหนดสำหรับการสกัดกั้นสตริง
เราทุกคนมาที่นี่ทำไมไม่ก้าวไปข้างหน้า?
ดังนั้นฉันพยายามค้นหาซอร์สโค้ด V8 บางตัวเพื่อดูว่าฉันสามารถหาวิธีการใช้งานที่เฉพาะเจาะจงได้หรือไม่ ฉันพบรหัสที่เกี่ยวข้องลิงค์ซอร์สโค้ด
นี่คือบางส่วนของพวกเขา:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชัน stringsplitjs (ตัวคั่น, ขีด จำกัด ) {
-
-
// ตัวคั่นเป็นสตริง
if (! is_regexp (ตัวคั่น)) {
var separator_string = to_string_inline (ตัวคั่น);
ถ้า (จำกัด === 0) return [];
// ECMA-262 บอกว่าหากตัวคั่นไม่ได้กำหนดไว้ผลลัพธ์ควร
// เป็นอาร์เรย์ขนาด 1 ที่มีสตริงทั้งหมด
if (is_undefined (ตัวคั่น)) ส่งคืน [หัวเรื่อง];
var separator_length = separator_string.length;
// ตัวคั่นเป็นสตริงที่ว่างเปล่าซึ่งส่งคืนอาร์เรย์อักขระโดยตรง
if (separator_length === 0) return %stringtoarray (หัวเรื่อง, ขีด จำกัด );
var result = %stringsplit (หัวเรื่อง, separator_string, ขีด จำกัด );
ผลการกลับมา;
-
ถ้า (จำกัด === 0) return [];
// เมื่อตัวคั่นเป็นนิพจน์ทั่วไปโทร StringSplitonRegexp
return stringsplitonregexp (หัวเรื่อง, ตัวคั่น, ขีด จำกัด , ความยาว);
-
// รหัสหลายรหัสถูกละไว้ที่นี่
ฉันพบในรหัสว่าเมื่อเติมอาร์เรย์วิธี %_substring จะถูกเรียกให้สกัดกั้นสตริง น่าเสียดายที่ฉันไม่พบคำจำกัดความที่เกี่ยวข้อง หากมีนักเรียนที่พบมันโปรดแจ้งให้เราทราบ อย่างไรก็ตามฉันพบว่าวิธี stringsubstring ที่สอดคล้องกับวิธีการย่อยใน JavaScript จะเรียกวิธี %_substring และส่งคืนผลลัพธ์ ถ้า 'ABC'.SubString (1,1) ส่งคืน "" นั่นหมายความว่าวิธี %_substring จะกลับมา "" เมื่อตำแหน่งเริ่มต้นและตำแหน่งสิ้นสุดเหมือนกัน คุณสามารถบอกผลลัพธ์ได้โดยลองดู
ดังนั้นตำแหน่งเริ่มต้นจะเท่ากับตำแหน่งสิ้นสุด (เช่น Q === p) เมื่อใด ฉันทำตามขั้นตอนข้างต้นทีละขั้นตอนและพบในที่สุด:
•เมื่อสตริงต้นฉบับตรงกับตัวคั่นหนึ่งครั้งทันทีหลังจากนั้นตำแหน่งถัดไปของสตริง S จะตรงกับตัวคั่น ตัวอย่างเช่น: 'abbbc'.split (' b '),' abbbc'.split (/(b) {1}/)
•อีกกรณีหนึ่งคืออักขระหนึ่งหรือหลายตัวที่จุดเริ่มต้นของสตริงตรงกับตัวคั่น ตัวอย่างเช่น: 'abc'.split (' a '),' abc'.split (/ab/)
•มีอีกกรณีหนึ่งที่หนึ่งหรือหลายสายในตอนท้ายของสตริงตรงกับตัวคั่นและขั้นตอนที่เกี่ยวข้องคือขั้นตอนที่ 14
ตัวอย่างเช่น: 'abc'.split (' c '),' abc'.split (/bc/)
นอกจากนี้เมื่อใช้นิพจน์ทั่วไปเป็นตัวคั่นที่ไม่ได้กำหนดอาจปรากฏในผลลัพธ์ที่ส่งคืน
ตัวอย่างเช่น: 'abc'.split (/(d)*/)
มาดูตัวอย่างที่จุดเริ่มต้น มันเป็นไปตามสถานการณ์ข้างต้นหรือไม่?
นอกหัวข้อ
นี่เป็นครั้งแรกที่ฉันได้อ่านข้อกำหนดมาตรฐานของ Ecmascript อย่างระมัดระวัง กระบวนการอ่านหนังสือนั้นเจ็บปวดมาก แต่หลังจากเข้าใจแล้วฉันรู้สึกมีความสุขมาก ขอบคุณสำหรับคำถามนี้และคำถามติดตามผล
โดยวิธีการเมื่อใช้นิพจน์ทั่วไปเป็นตัวคั่นตัวปรับเปลี่ยน Global Global Modifier G จะถูกละเว้นซึ่งก็เป็นกำไรเพิ่มเติม