ฟีเจอร์นิพจน์ทั่วไปที่กำลังจะเปิดตัว

Jakob Gruber
Yang Guo

ES2015 นำเสนอฟีเจอร์ใหม่ๆ มากมายสำหรับภาษา JavaScript ซึ่งรวมถึงการปรับปรุงที่สำคัญในไวยากรณ์นิพจน์ทั่วไปด้วยแฟล็ก Unicode (/u) และแบบติดหนึบ (/y) แต่การพัฒนายังไม่หยุดนับจากนั้น การทำงานร่วมกับสมาชิกคนอื่นๆ ใน TC39 (เนื้อความมาตรฐานของ ECMAScript) อย่างใกล้ชิด ทีม V8 ได้เสนอและร่วมออกแบบฟีเจอร์ใหม่ๆ หลายรายการเพื่อทำให้การแสดงออกตามปกติมีประสิทธิภาพยิ่งขึ้น

ขณะนี้เรากำลังเสนอฟีเจอร์เหล่านี้เพื่อให้รวมอยู่ในข้อกำหนด JavaScript แม้ว่าข้อเสนอจะไม่ได้รับการยอมรับโดยสมบูรณ์ แต่อยู่ในระยะที่ 3 ในกระบวนการ TC39 แล้ว เราได้นำฟีเจอร์ดังกล่าวมาใช้หลังการประกาศ (ดูด้านล่าง) เพื่อที่จะให้ความคิดเห็นเกี่ยวกับการออกแบบและการติดตั้งใช้งานแก่ผู้เขียนข้อเสนอที่เกี่ยวข้องได้ทันท่วงทีก่อนที่จะสรุปผล

บล็อกโพสต์นี้จะแสดงตัวอย่างอนาคตที่น่าตื่นเต้นนี้ หากต้องการติดตามตัวอย่างที่กำลังจะมีขึ้น ให้เปิดใช้ฟีเจอร์ JavaScript แบบทดลองที่ chrome://flags/#enable-javascript-harmony

บันทึกที่มีชื่อ

นิพจน์ทั่วไปอาจมีการตรวจจับสิ่งที่เรียกว่า (หรือกลุ่ม) ซึ่งสามารถจับบางส่วนของข้อความที่ตรงกันได้ จนถึงตอนนี้ นักพัฒนาซอฟต์แวร์จะดูได้เพียง การบันทึกเหล่านี้ด้วยดัชนี ซึ่งพิจารณาจากตำแหน่งของ การจับภาพภายในรูปแบบ

const pattern = /(\d{4})-(\d{2})-(\d{2})/u;
const result = pattern.exec('2017-07-10');
// result[0] === '2017-07-10'
// result[1] === '2017'
// result[2] === '07'
// result[3] === '10'

แต่เป็นที่รู้กันดีว่านิพจน์ทั่วไปนั้นอ่าน เขียน และดูแลรักษาได้ยากอยู่แล้ว และการอ้างอิงแบบตัวเลขยังเพิ่มความแทรกซ้อนเพิ่มเติมได้ ตัวอย่างเช่น ในรูปแบบที่ยาวกว่า การระบุดัชนีของการจับภาพที่เฉพาะเจาะจงอาจเป็นเรื่องยาก

/(?:(.)(.(?<=[^(])(.)))/  // Index of the last capture?

และที่แย่กว่านั้น การเปลี่ยนแปลงรูปแบบอาจเปลี่ยนดัชนีการจับภาพที่มีอยู่ทั้งหมดได้

/(a)(b)(c)\3\2\1/     // A few simple numbered backreferences.
/(.)(a)(b)(c)\4\3\2/  // All need to be updated.

การจับที่มีชื่อเป็นฟีเจอร์ที่กำลังจะเปิดตัวซึ่งจะช่วยบรรเทาปัญหาเหล่านี้โดยการอนุญาตให้นักพัฒนาซอฟต์แวร์ตั้งชื่อเพื่อจับภาพ ไวยากรณ์จะคล้ายกับ Perl, Java, .Net และ Ruby ดังนี้

const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = pattern.exec('2017-07-10');
// result.groups.year === '2017'
// result.groups.month === '07'
// result.groups.day === '10'

นอกจากนี้ ยังอ้างอิงการบันทึกที่มีชื่อได้ด้วย Backreferences ที่มีชื่อและผ่านทาง String.prototype.replace ดังนี้

// Named backreferences.
/(?<LowerCaseX>x)y\k<LowerCaseX>/.test('xyx');  // true

// String replacement.
const pattern = /(?<fst>a)(?<snd>b)/;
'ab'.replace(pattern, '$<snd>$<fst>');                              // 'ba'
'ab'.replace(pattern, (m, p1, p2, o, s, {fst, snd}) => fst + snd);  // 'ba'

ดูรายละเอียดทั้งหมดของฟีเจอร์ใหม่นี้ได้ในข้อเสนอข้อกำหนด

ธงจุดทั้งหมด

โดยค่าเริ่มต้น อะตอม . ในนิพจน์ทั่วไปจะจับคู่อักขระใดก็ได้ ยกเว้นอักขระต่อท้ายบรรทัด

/foo.bar/u.test('foo\nbar');   // false

ข้อเสนอจะแนะนำโหมดจุดทั้งหมด ซึ่งเปิดใช้ผ่านแฟล็ก /s ในโหมดเครื่องหมายจุด . จะตรงกับตัวสิ้นสุดบรรทัดด้วย

/foo.bar/su.test('foo\nbar');  // true

ดูรายละเอียดทั้งหมดของฟีเจอร์ใหม่นี้ได้ในข้อเสนอข้อกำหนด

การกำหนดอักขระหลีกพร็อพเพอร์ตี้ Unicode

เมื่อเริ่มใช้การรับรู้ Unicode ในปี 2015 เป็นต้นมา จู่ๆ ก็มีอักขระอื่นๆ ที่ถือว่าเป็นตัวเลขขึ้นมาอีกจำนวนมาก เช่น ตัวเลขในวงกลมเลข 1:1 หรืออักขระที่เป็นคำ เช่น อักษรจีนสำหรับคำว่าหิมะ 雪

ทั้ง 2 รายการนี้จับคู่กับ \d หรือ \w ไม่ได้ การเปลี่ยนความหมายของชวเลขเหล่านี้จะทำให้รูปแบบนิพจน์ทั่วไปที่มีอยู่ใช้ไม่ได้

แต่เราเปิดตัวลำดับการยกเว้นพร็อพเพอร์ตี้ใหม่แทน โปรดทราบว่าแพ็กเกจเหล่านี้จะพร้อมใช้งานสำหรับนิพจน์ทั่วไปที่รับรู้ Unicode ซึ่งแสดงโดยแฟล็ก /u เท่านั้น

/\p{Number}/u.test('①');      // true
/\p{Alphabetic}/u.test('雪');  // true

ระบบจะจับคู่ผกผันกับ \P

/\P{Number}/u.test('①');      // false
/\P{Alphabetic}/u.test('雪');  // false

Unicode Consortium กำหนดพร็อพเพอร์ตี้เพิ่มเติมมากมาย เช่น สัญลักษณ์ทางคณิตศาสตร์หรืออักขระฮิรางานะภาษาญี่ปุ่น

/^\p{Math}+$/u.test('∛∞∉');                            // true
/^\p{Script_Extensions=Hiragana}+$/u.test('ひらがな');  // true

ดูรายการคลาสพร็อพเพอร์ตี้ Unicode ทั้งหมดที่รองรับได้ในข้อเสนอข้อกำหนดปัจจุบัน ดูตัวอย่างเพิ่มเติมได้ที่บทความที่ให้ข้อมูลนี้

การยืนยันที่อยู่เบื้องหลัง

การยืนยัน Lookahead เป็นส่วนหนึ่งของไวยากรณ์นิพจน์ทั่วไปของ JavaScript มาตั้งแต่ต้น ซึ่งท้ายที่สุดแล้ว คู่สนทนาซึ่งดูเบื้องหลังการยืนยันจะถูก เปิดตัว หลายคนอาจจำได้ว่านี่เป็นส่วนหนึ่งของ V8 มาสักพักแล้วนะ เรายังใช้การยืนยันเบื้องหลังขั้นสูงเพื่อนำแฟล็ก Unicode ที่ระบุใน ES2015 ไปใช้อีกด้วย

ชื่อนี้อธิบายความหมายได้ค่อนข้างดีอยู่แล้ว เครื่องมือนี้จะเสนอวิธีจำกัดรูปแบบให้จับคู่ก็ต่อเมื่อมีการค้นหาก่อนหน้าด้วยรูปแบบในกลุ่ม Lookbehind เท่านั้น ซึ่งจะมีทั้งรสชาติที่ตรงกันและไม่ตรงกัน

/(?<=\$)\d+/.exec('$1 is worth about ¥123');  // ['1']
/(?<!\$)\d+/.exec('$1 is worth about ¥123');  // ['123']

ดูรายละเอียดเพิ่มเติมได้ในบล็อกโพสต์ก่อนหน้าสำหรับดูเบื้องหลังการยืนยันและตัวอย่างในกรอบการทดสอบ V8 โดยเฉพาะ

กิตติกรรมประกาศ

บล็อกโพสต์นี้จะไม่สมบูรณ์หากเราไม่กล่าวถึงบุคคลบางส่วนที่ทำงานอย่างหนักเพื่อให้บรรลุเป้าหมาย โดยเฉพาะผู้นำด้านภาษาอย่าง Mathias Bynens, Dan Ehrenberg, Claude Pache, Brian Terlson, Thomas Wood, Gorkem Yakin, และ Irregexp กูรูเกี่ยวกับการใช้งานของ Erik Corry และทุกคน Erik Corry}

เราหวังว่าคุณจะตื่นเต้นเกี่ยวกับฟีเจอร์ใหม่ของนิพจน์ทั่วไปเหล่านี้เหมือนกับเรา