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

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

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

บล็อกโพสต์นี้จะแสดงตัวอย่างของอนาคตที่น่าตื่นเต้นนี้ หากต้องการทําตามตัวอย่างที่กําลังจะเผยแพร่ ให้เปิดใช้ฟีเจอร์ 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'

นอกจากนี้ คุณยังอ้างอิงการจับที่ชื่อได้ด้วยการอ้างอิงย้อนกลับที่มีชื่อและผ่าน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'

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

Flag dotAll

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

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

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

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

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

การหนีค่าพร็อพเพอร์ตี้ Unicode

เมื่อมีการนำการรับรู้ Unicode มาใช้ใน ES2015 อักขระที่อาจถือเป็นตัวเลขก็เพิ่มขึ้นอย่างฉับพลัน เช่น ตัวเลข 1 ที่มีวงกลมล้อมรอบ ① หรืออักขระที่เป็นคำ เช่น อักขระจีนสำหรับ "หิมะ" 雪

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

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

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

คุณสามารถจับคู่ค่าผกผันด้วย \P

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

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

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

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

การยืนยันการมองย้อนกลับ

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

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

/(?<=\$)\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 รวมถึงทุกคนที่มีส่วนร่วมในข้อกำหนดของภาษาและการใช้งานฟีเจอร์เหล่านี้ของ V8

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