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
เราหวังว่าคุณจะตื่นเต้นกับฟีเจอร์นิพจน์ทั่วไปใหม่เหล่านี้เหมือนกับเรา