ฉันไม่เห็นคำตอบใด ๆ ในคำตอบที่มีอยู่ของประเด็นที่เกี่ยวข้องกับรหัสระนาบคล้ายดาวหรือการทำให้เป็นสากล “ ตัวพิมพ์ใหญ่” ไม่ได้หมายถึงสิ่งเดียวกันในทุกภาษาโดยใช้สคริปต์ที่กำหนด
ตอนแรกฉันไม่เห็นคำตอบใด ๆ เกี่ยวกับประเด็นที่เกี่ยวข้องกับรหัสระนาบคล้ายดาว มีอยู่หนึ่งอัน แต่มันก็ถูกฝังอยู่เล็กน้อย (เช่นนี้ฉันเดาได้!)
ฟังก์ชั่นที่เสนอส่วนใหญ่มีลักษณะดังนี้:
function capitalizeFirstLetter(str) {
return str[0].toUpperCase() + str.slice(1);
}
อย่างไรก็ตามตัวละครบางตัวอยู่นอก BMP (ระนาบหลายภาษาพื้นฐานรหัสจุด U + 0 ถึง U + FFFF) ตัวอย่างเช่นใช้ข้อความ Deseret นี้:
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉"); // "𐐶𐐲𐑌𐐼𐐲𐑉"
อักขระตัวแรกที่นี่ไม่สามารถใช้ประโยชน์ได้เนื่องจากคุณสมบัติการจัดทำดัชนีของสตริงไม่สามารถเข้าถึง“ ตัวอักษร” หรือจุดรหัส * พวกเขาเข้าถึงหน่วยรหัส UTF-16 สิ่งนี้เป็นจริงเช่นกันเมื่อมีการตัด - ค่าดัชนีชี้ไปที่หน่วยรหัส
มันเป็นไปได้ว่าหน่วยรหัส UTF-16 เป็น 1: 1 โดยมีรหัส USV อยู่ในสองช่วงคือ U + 0 ถึง U + D7FF และ U + E000 ถึง U + FFFF อักขระที่ใส่ซองส่วนใหญ่อยู่ในช่วงสองช่วงนั้น แต่ไม่ใช่ทั้งหมด
จาก ES2015 เป็นต้นไปการจัดการกับสิ่งนี้กลายเป็นเรื่องง่ายขึ้นเล็กน้อย String.prototype[@@iterator]
ให้สตริงที่สอดคล้องกับจุดโค้ด ** ตัวอย่างเช่นเราสามารถทำสิ่งนี้:
function capitalizeFirstLetter([ first, ...rest ]) {
return [ first.toUpperCase(), ...rest ].join('');
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
สำหรับสตริงที่ยาวกว่านี้อาจไม่ได้มีประสิทธิภาพมากนัก - เราไม่จำเป็นต้องย้ำส่วนที่เหลือ เราสามารถใช้String.prototype.codePointAt
เพื่อรับจดหมายฉบับแรก (เป็นไปได้) แต่เรายังต้องพิจารณาว่าส่วนใดควรเริ่มต้น วิธีหนึ่งในการหลีกเลี่ยงการวนซ้ำส่วนที่เหลือคือการทดสอบว่า codepoint ตัวแรกอยู่นอก BMP หรือไม่ ถ้ามันไม่ใช่ชิ้นเริ่มต้นที่ 1 และถ้าเป็นชิ้นเริ่มต้นที่ 2
function capitalizeFirstLetter(str) {
const firstCP = str.codePointAt(0);
const index = firstCP > 0xFFFF ? 2 : 1;
return String.fromCodePoint(firstCP).toUpperCase() + str.slice(index);
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
คุณสามารถใช้คณิตศาสตร์ระดับบิตแทนที่> 0xFFFF
นั่นได้ แต่มันอาจจะง่ายกว่าที่จะเข้าใจวิธีนี้และอาจบรรลุสิ่งเดียวกัน
นอกจากนี้เรายังสามารถทำให้งานนี้ใน ES5 และด้านล่างโดยใช้ตรรกะนั้นอีกเล็กน้อยหากจำเป็น ไม่มีวิธีที่แท้จริงใน ES5 สำหรับการทำงานกับ codepoints ดังนั้นเราต้องทดสอบด้วยตนเองว่าหน่วยรหัสแรกเป็นตัวแทน ****:
function capitalizeFirstLetter(str) {
var firstCodeUnit = str[0];
if (firstCodeUnit < '\uD800' || firstCodeUnit > '\uDFFF') {
return str[0].toUpperCase() + str.slice(1);
}
return str.slice(0, 2).toUpperCase() + str.slice(2);
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
ในตอนแรกฉันยังกล่าวถึงข้อควรพิจารณาเกี่ยวกับความเป็นสากล บางส่วนของเหล่านี้เป็นเรื่องยากมากที่จะบัญชีสำหรับเพราะพวกเขาต้องใช้ความรู้ไม่เพียง แต่สิ่งที่ภาษาจะถูกใช้ แต่อาจต้องใช้ความรู้เฉพาะของคำในภาษา ตัวอย่างเช่น Digip ไอริช "mb" ใช้ตัวพิมพ์ใหญ่เป็น "mB" ในตอนต้นของคำ อีกตัวอย่างหนึ่งคือ Eszett เยอรมันไม่เคยเริ่มคำ (afaik) แต่ก็ยังช่วยอธิบายปัญหาได้ ตัวพิมพ์เล็ก eszett ("ß") ใช้อักษรตัวพิมพ์ใหญ่เป็น "SS" แต่ "SS" อาจเป็นตัวพิมพ์เล็กเป็น "ß" หรือ "ss" - คุณจำเป็นต้องมีความรู้ภาษาเยอรมันที่ถูกต้อง!
ตัวอย่างที่มีชื่อเสียงที่สุดของปัญหาประเภทนี้อาจเป็นภาษาตุรกี ในภาษาละตินตุรกีรูปแบบตัวพิมพ์ใหญ่ของ i คือİในขณะที่รูปแบบตัวพิมพ์เล็กของฉันคือı - มันเป็นตัวอักษรสองตัวที่แตกต่างกัน โชคดีที่เรามีวิธีการบัญชีสำหรับสิ่งนี้:
function capitalizeFirstLetter([ first, ...rest ], locale) {
return [ first.toLocaleUpperCase(locale), ...rest ].join('');
}
capitalizeFirstLetter("italy", "en") // "Italy"
capitalizeFirstLetter("italya", "tr") // "İtalya"
ในเบราว์เซอร์แท็กภาษาที่ผู้ใช้ต้องการมากที่สุดจะถูกระบุด้วยnavigator.language
รายการตามลำดับที่ต้องการnavigator.languages
และภาษาขององค์ประกอบ DOM ที่กำหนดสามารถรับได้ (โดยปกติ) พร้อมด้วยObject(element.closest('[lang]')).lang || YOUR_DEFAULT_HERE
เอกสารหลายภาษา
ในเอเจนต์ที่สนับสนุนคลาสอักขระคุณสมบัติ Unicode ใน RegExp ซึ่งเปิดตัวใน ES2018 เราสามารถล้างข้อมูลเพิ่มเติมได้โดยแสดงสิ่งที่ตัวละครที่เราสนใจโดยตรง:
function capitalizeFirstLetter(str, locale=navigator.language) {
return str.replace(/^\p{CWU}/u, char => char.toLocaleUpperCase(locale));
}
สิ่งนี้อาจถูกปรับแต่งเล็กน้อยเพื่อจัดการกับการใช้อักษรตัวพิมพ์ใหญ่หลายคำในสตริงด้วยความแม่นยำที่ค่อนข้างดี กระบวนการCWU
หรือการเปลี่ยนแปลงคุณสมบัติของตัวอักษรหรืออักขระ___enhen_Uppercasedตรงกับจุดรหัสทั้งหมดซึ่งก็เปลี่ยนเมื่อตัวพิมพ์ใหญ่ เราสามารถลองใช้ตัวอักษร digraph ที่มีหัวเรื่องเช่นภาษาดัตช์ij :
capitalizeFirstLetter('ijsselmeer'); // "IJsselmeer"
ในช่วงเวลาของการเขียน (ก.พ. 2020) Firefox / Spidermonkey ยังไม่ได้ใช้คุณสมบัติ RegExp ที่แนะนำในช่วงสองปีที่ผ่านมา ***** คุณสามารถตรวจสอบสถานะปัจจุบันของคุณลักษณะนี้ที่โต๊ะ compat Kangax บาเบลสามารถรวบรวมตัวอักษร RegExp ด้วยการอ้างอิงคุณสมบัติไปยังรูปแบบที่เทียบเท่าโดยไม่มีพวกเขา แต่โปรดทราบว่ารหัสผลลัพธ์อาจมีขนาดใหญ่มาก
ในทุกโอกาสคนที่ถามคำถามนี้จะไม่เกี่ยวข้องกับการใช้ตัวพิมพ์ใหญ่หรือการทำให้เป็นสากล แต่ก็เป็นเรื่องดีที่จะต้องตระหนักถึงปัญหาเหล่านี้เพราะมีโอกาสที่ดีที่คุณจะพบพวกเขาในที่สุดแม้ว่าพวกเขาจะไม่กังวล พวกเขาไม่ใช่กรณี "edge" หรือมากกว่านั้นไม่ใช่กรณีแบบ edge -definition - มีทั้งประเทศที่คนส่วนใหญ่พูดภาษาตุรกีอยู่แล้วและการทำให้หน่วยโค้ดกับ codepoints เป็นแหล่งของแมลงที่พบบ่อย (โดยเฉพาะกับ เกี่ยวกับอิโมจิ) ทั้งสตริงและภาษาค่อนข้างซับซ้อน!
* หน่วยรหัสของ UTF-16 / UCS2 นั้นก็เป็น Unicode code points ในแง่ที่ว่าเช่น U + D800 เป็นจุดรหัสทางเทคนิค แต่นั่นไม่ใช่สิ่งที่ "หมายถึง" ที่นี่ ... เรียงลำดับ ... แม้ว่ามันจะสวย เลือน สิ่งที่ตัวแทนจะไม่แน่นอนคือ USVs (ค่าสเกลาร์ Unicode)
** แม้ว่าหน่วยรหัสตัวแทนคือ“ กำพร้า” - กล่าวคือไม่ได้เป็นส่วนหนึ่งของคู่ตรรกะ - คุณยังสามารถรับตัวแทนที่นี่ได้เช่นกัน
*** อาจจะ. ฉันยังไม่ได้ทดสอบ หากคุณไม่ได้พิจารณาว่าการใช้อักษรตัวพิมพ์ใหญ่เป็นคอขวดที่มีความหมายฉันอาจจะไม่เหงื่อออก - เลือกสิ่งที่คุณเชื่อว่าชัดเจนที่สุดและอ่านได้
**** ฟังก์ชั่นดังกล่าวอาจต้องการทดสอบทั้งหน่วยแรกและหน่วยที่สองแทนที่จะเป็นหน่วยแรกเนื่องจากเป็นไปได้ว่าหน่วยแรกเป็นตัวแทนกำพร้า ตัวอย่างเช่นอินพุต "\ uD800x" จะใช้ประโยชน์ X ตามที่เป็นอยู่ซึ่งอาจเป็นหรือไม่คาดหวังก็ได้
***** นี่คือปัญหา Bugzillaหากคุณต้องการติดตามความคืบหน้ามากขึ้นโดยตรง