Saya tidak melihat ada disebutkan dalam jawaban yang ada masalah yang berkaitan dengan poin kode pesawat astral atau internasionalisasi. "Huruf Besar" tidak berarti hal yang sama di setiap bahasa menggunakan skrip yang diberikan.
Awalnya saya tidak melihat jawaban yang membahas masalah yang terkait dengan poin kode pesawat astral. Ada satu , tapi agak terkubur (seperti ini, saya kira!)
Sebagian besar fungsi yang diusulkan terlihat seperti ini:
function capitalizeFirstLetter(str) {
return str[0].toUpperCase() + str.slice(1);
}
Namun, beberapa karakter yang berada di luar BMP (bidang multibahasa dasar, titik kode U + 0 hingga U + FFFF). Misalnya ambil teks Deseret ini:
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉"); // "𐐶𐐲𐑌𐐼𐐲𐑉"
Karakter pertama di sini gagal menjadi huruf besar karena properti string yang diindeks array tidak mengakses "karakter" atau titik kode *. Mereka mengakses unit kode UTF-16. Ini benar juga ketika mengiris - nilai indeks menunjuk pada unit kode.
Kebetulan bahwa unit kode UTF-16 adalah 1: 1 dengan titik kode USV dalam dua rentang, U + 0 hingga U + D7FF dan U + E000 ke U + FFFF inklusif. Sebagian besar karakter berhubung jatuh ke dalam dua rentang, tetapi tidak semuanya.
Dari ES2015 dan seterusnya, berurusan dengan ini menjadi sedikit lebih mudah. String.prototype[@@iterator]
menghasilkan string yang sesuai dengan poin kode **. Jadi misalnya, kita bisa melakukan ini:
function capitalizeFirstLetter([ first, ...rest ]) {
return [ first.toUpperCase(), ...rest ].join('');
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
Untuk string yang lebih lama, ini mungkin bukan *** yang sangat efisien - kita tidak benar-benar perlu untuk mengulanginya. Kita dapat menggunakan String.prototype.codePointAt
untuk mendapatkan surat pertama (mungkin) itu, tetapi kita masih harus menentukan di mana potongan harus dimulai. Salah satu cara untuk menghindari iterasi sisanya adalah dengan menguji apakah codepoint pertama berada di luar BMP; jika tidak, irisan dimulai pada 1, dan jika ya, irisan dimulai pada 2.
function capitalizeFirstLetter(str) {
const firstCP = str.codePointAt(0);
const index = firstCP > 0xFFFF ? 2 : 1;
return String.fromCodePoint(firstCP).toUpperCase() + str.slice(index);
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
Anda bisa menggunakan matematika bitwise daripada di > 0xFFFF
sana, tetapi mungkin lebih mudah untuk memahami cara ini dan juga akan mencapai hal yang sama.
Kami juga dapat membuat ini bekerja di ES5 dan di bawah dengan mengambil logika itu sedikit lebih jauh jika perlu. Tidak ada metode intrinsik dalam ES5 untuk bekerja dengan codepoint, jadi kita harus menguji secara manual apakah unit kode pertama adalah pengganti ****:
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("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
Pada awalnya saya juga menyebutkan pertimbangan internasionalisasi. Beberapa di antaranya sangat sulit untuk diperhitungkan karena mereka membutuhkan pengetahuan tidak hanya tentang bahasa apa yang digunakan, tetapi juga mungkin memerlukan pengetahuan khusus tentang kata-kata dalam bahasa tersebut. Misalnya, digraf Irlandia "mb" menggunakan huruf kapital sebagai "mB" pada awal kata. Contoh lain, eszett Jerman, tidak pernah memulai kata (afaik), tetapi masih membantu menggambarkan masalahnya. Eszett huruf kecil ("ß") menggunakan huruf kapital untuk "SS," tetapi "SS" dapat menjadi huruf kecil menjadi "ß" atau "ss" - Anda memerlukan pengetahuan out-of-band dari bahasa Jerman untuk mengetahui mana yang benar!
Contoh paling terkenal dari masalah semacam ini, mungkin, adalah bahasa Turki. Dalam bahasa Latin Turki, bentuk huruf kapital dari i adalah İ, sedangkan bentuk huruf kecil dari I adalah ı - keduanya adalah huruf yang berbeda. Untungnya kami memiliki cara untuk menjelaskan hal ini:
function capitalizeFirstLetter([ first, ...rest ], locale) {
return [ first.toLocaleUpperCase(locale), ...rest ].join('');
}
capitalizeFirstLetter("italy", "en") // "Italy"
capitalizeFirstLetter("italya", "tr") // "İtalya"
Di browser, tag bahasa yang paling disukai pengguna ditunjukkan oleh navigator.language
, daftar menurut preferensi ditemukan di navigator.languages
, dan bahasa elemen DOM yang diberikan dapat diperoleh (biasanya) dengan Object(element.closest('[lang]')).lang || YOUR_DEFAULT_HERE
dokumen multi bahasa.
Di agen yang mendukung kelas karakter properti Unicode di RegExp, yang diperkenalkan di ES2018, kami dapat membersihkan hal-hal lebih lanjut dengan secara langsung mengekspresikan karakter apa yang kami minati:
function capitalizeFirstLetter(str, locale=navigator.language) {
return str.replace(/^\p{CWU}/u, char => char.toLocaleUpperCase(locale));
}
Ini bisa sedikit di-tweak untuk menangani kapitalisasi beberapa kata dalam sebuah string dengan akurasi yang cukup baik. Properti CWU
atau Changes_When_Uppercased karakter cocok dengan semua titik kode yang, baik, berubah ketika huruf besar. Kita dapat mencoba ini dengan karakter digraf titlecased seperti Belanda ij misalnya:
capitalizeFirstLetter('ijsselmeer'); // "IJsselmeer"
Pada saat penulisan (Feb 2020), Firefox / Spidermonkey belum mengimplementasikan fitur RegExp yang diperkenalkan dalam dua tahun terakhir *****. Anda dapat memeriksa status terkini dari fitur ini di tabel compat Kangax . Babel dapat mengkompilasi literal RegExp dengan referensi properti ke pola yang setara tanpa mereka, tetapi perlu diketahui bahwa kode yang dihasilkan mungkin sangat besar.
Dalam semua kemungkinan, orang yang mengajukan pertanyaan ini tidak akan peduli dengan kapitalisasi Deseret atau internasionalisasi. Tapi ada baiknya menyadari masalah ini karena ada kemungkinan Anda akan menemukan mereka pada akhirnya, bahkan jika mereka tidak masalah saat ini. Mereka bukan kasus "tepi", atau lebih tepatnya, mereka bukan kasus tepi menurut definisi - ada seluruh negara di mana kebanyakan orang berbicara bahasa Turki, dan menggabungkan unit kode dengan codepoint adalah sumber bug yang cukup umum (terutama dengan berkaitan dengan emoji). Baik string dan bahasa cukup rumit!
* Unit kode UTF-16 / UCS2 juga merupakan titik kode Unicode dalam arti bahwa misalnya U + D800 secara teknis merupakan titik kode, tetapi bukan itu "artinya" di sini ... semacam ... meskipun ... kabur. Apa yang pasti bukan pengganti adalah USV (nilai skalar Unicode).
** Meskipun jika unit kode pengganti "yatim" - yaitu, bukan bagian dari pasangan logis - Anda masih bisa mendapatkan pengganti di sini juga.
*** mungkin. Saya belum mengujinya. Kecuali jika Anda telah menentukan kapitalisasi adalah hambatan yang berarti, saya mungkin tidak akan berkeringat - pilih apa pun yang Anda yakini paling jelas dan mudah dibaca.
**** fungsi seperti itu mungkin ingin menguji unit kode pertama dan kedua bukan hanya yang pertama, karena mungkin unit pertama adalah pengganti yatim piatu. Misalnya input "\ uD800x" akan menjadi huruf kapital X apa adanya, yang mungkin atau mungkin tidak diharapkan.
***** Inilah masalah Bugzilla jika Anda ingin mengikuti progres lebih langsung.