Kode ini:
string a = "abc";
string b = "A𠈓C";
Console.WriteLine("Length a = {0}", a.Length);
Console.WriteLine("Length b = {0}", b.Length);
output:
Length a = 3
Length b = 4
Mengapa? Satu-satunya hal yang dapat saya bayangkan adalah bahwa karakter Cina panjangnya 2 byte dan .Length
metode mengembalikan jumlah byte.
𠈓
adalah 131603, dan karena chars adalah byte yang tidak ditandai, itu berarti Anda dapat mencapai nilai itu dalam 2 karakter daripada 4 (unsigned 16 bit nilai maks adalah 65535 (atau 65536 variasi) dan menggunakan 2 chars untuk mewakili itu memungkinkan untuk jumlah maksimum variasi bukan 65536 * 2 (131072) tetapi lebih tepatnya 65536 * 65536 variasi (4.294.967.296, efektif nilai 32 bit)Jawaban:
Semua orang memberikan jawaban permukaan, tetapi ada alasan yang lebih dalam juga: jumlah "karakter" adalah pertanyaan yang sulit untuk didefinisikan dan bisa sangat mahal untuk dihitung, sedangkan properti panjang harus cepat.
Mengapa sulit untuk didefinisikan? Yah, ada beberapa opsi dan tidak ada yang benar-benar lebih valid daripada yang lain:
Jumlah unit kode (byte atau potongan data ukuran tetap lainnya; C # dan Windows biasanya menggunakan UTF-16 sehingga mengembalikan jumlah potongan dua-byte) pasti relevan, karena komputer masih perlu menangani data dalam bentuk itu untuk banyak tujuan (menulis ke file, misalnya, peduli dengan byte daripada karakter)
Jumlah Unicode codepoints cukup mudah untuk dihitung (walaupun O (n) karena Anda harus memindai string untuk pasangan pengganti) dan mungkin penting bagi editor teks .... tetapi sebenarnya tidak sama dengan jumlah karakter dicetak di layar (disebut graphemes). Misalnya, beberapa huruf beraksen dapat direpresentasikan dalam dua bentuk: satu titik kode tunggal, atau dua titik yang dipasangkan bersama, satu mewakili huruf, dan satu mengatakan "tambahkan aksen ke surat mitra saya". Apakah pasangan itu dua karakter atau satu? Anda dapat menormalkan string untuk membantu dengan ini, tetapi tidak semua huruf yang valid memiliki representasi codepoint tunggal.
Bahkan jumlah grafik tidak sama dengan panjang string yang dicetak, yang tergantung pada font di antara faktor-faktor lain, dan karena beberapa karakter dicetak dengan beberapa tumpang tindih dalam banyak font (kerning), panjang string di layar toh belum tentu sama dengan jumlah dari panjang grapheme pula!
Beberapa titik Unicode bahkan bukan karakter dalam arti tradisional, melainkan semacam penanda kontrol. Seperti penanda urutan byte atau indikator kanan-ke-kiri. Apakah ini diperhitungkan?
Singkatnya, panjang string sebenarnya adalah pertanyaan yang sangat rumit dan menghitungnya bisa memakan banyak waktu CPU serta tabel data.
Apalagi apa gunanya? Mengapa metrik ini penting? Yah, hanya Anda yang bisa menjawabnya untuk kasus Anda, tetapi secara pribadi, saya menemukan mereka pada umumnya tidak relevan. Membatasi entri data yang saya temukan lebih logis dilakukan oleh batas byte, karena itulah yang perlu ditransfer atau disimpan. Membatasi ukuran tampilan lebih baik dilakukan oleh perangkat lunak sisi tampilan - jika Anda memiliki 100 piksel untuk pesan, berapa banyak karakter yang Anda pas tergantung pada font, dll., Yang tidak diketahui oleh perangkat lunak lapisan data. Akhirnya, mengingat kompleksitas standar unicode, Anda mungkin akan memiliki bug di ujung kasus jika Anda mencoba yang lain.
Jadi itu adalah pertanyaan yang sulit dengan tidak banyak penggunaan tujuan umum. Jumlah unit kode sepele untuk dihitung - itu hanya panjang array data yang mendasarinya - dan yang paling bermakna / berguna sebagai aturan umum, dengan definisi sederhana.
Itu sebabnya
b
memiliki panjang4
melampaui penjelasan permukaan "karena dokumentasi mengatakan demikian".sumber
Length
harus usang, untuk mempertahankan analogi dengan array.Dari dokumentasi dari
String.Length
properti:sumber
String b
), karena menggunakan representasi UTF-16 dalam array char. Ini adalah karakter 4 byte dalam UTF-8.Karakter Anda di indeks 1 dalam
"A𠈓C"
adalah SurrogatePairAnda dapat mencoba kode ini dan itu akan kembali
True
Metode Char.IsSurrogatePair (String, Int32)
Ini dijelaskan lebih lanjut dalam properti String.Length :
sumber
Seperti yang ditunjukkan oleh jawaban lain, bahkan jika ada 3 karakter yang terlihat mereka diwakili dengan 4
char
objek. Itulah sebabnyaLength
adalah 4 dan bukan 3.MSDN menyatakan itu
Namun jika yang Anda benar-benar ingin tahu adalah jumlah "elemen teks" dan bukan jumlah
Char
objek yang dapat Anda gunakanStringInfo
kelas.Anda juga dapat menghitung setiap elemen teks seperti ini
Menggunakan
foreach
pada string akan membagi "huruf" tengah menjadi duachar
objek dan hasil yang dicetak tidak akan sesuai dengan string.sumber
Itu karena
Length
properti mengembalikan jumlah objek char , bukan jumlah karakter unicode. Dalam kasus Anda, salah satu karakter Unicode diwakili oleh lebih dari satu objek char (SurrogatePair).sumber
Seperti yang orang lain katakan, itu bukan jumlah karakter dalam string tetapi jumlah objek Char. Karakter 𠈓 adalah kode titik U + 20213. Karena nilainya di luar kisaran tipe 16-bit, itu dikodekan dalam UTF-16 sebagai pasangan pengganti
D840 DE13
.Cara mendapatkan panjang karakter disebutkan dalam jawaban lain. Namun harus digunakan dengan hati-hati karena ada banyak cara untuk mewakili karakter di Unicode. "à" dapat berupa 1 karakter tersusun atau 2 karakter (a + diakritik). Normalisasi mungkin diperlukan seperti dalam kasus twitter .
Anda harus membaca ini
Minimum Mutlak Setiap Pengembang Perangkat Lunak Sepenuhnya, Pasti Harus Tahu Tentang Unicode dan Karakter (Tidak Ada Alasan!)
sumber
Ini karena
length()
hanya berfungsi untuk titik kode Unicode yang tidak lebih besar dariU+FFFF
. Kumpulan poin kode ini dikenal sebagai Basic Multilingual Plane (BMP) dan hanya menggunakan 2 byte.Poin kode Unicode di luar
BMP
diwakili dalam UTF-16 menggunakan pasangan pengganti 4 byte.Untuk menghitung jumlah karakter dengan benar (3), gunakan
StringInfo
sumber
Oke, di .Net dan C # semua string dikodekan sebagai UTF-16LE . A
string
disimpan sebagai urutan karakter. Setiapchar
mengenkapsulasi penyimpanan 2 byte atau 16 bit.Apa yang kita lihat "di atas kertas atau layar" sebagai satu huruf, karakter, mesin terbang, simbol, atau tanda baca dapat dianggap sebagai Elemen Teks tunggal. Seperti yang dijelaskan dalam Unicode Standard Annex # 29 UNICODE SEGMENTATION TEXT , setiap Elemen Teks diwakili oleh satu atau lebih Poin Kode. Daftar lengkap Kode dapat ditemukan di sini .
Setiap Poin Kode perlu dikodekan ke dalam biner untuk representasi internal oleh komputer. Seperti yang dinyatakan, masing-masing
char
menyimpan 2 byte. Poin Kode pada atau di bawahU+FFFF
ini dapat disimpan dalam satuchar
. Poin Kode di atasU+FFFF
disimpan sebagai pasangan pengganti, menggunakan dua karakter untuk mewakili satu Poin Kode.Mengingat apa yang kita ketahui sekarang dapat kita simpulkan, Elemen Teks dapat disimpan sebagai satu
char
, sebagai Pasangan Pengganti dari dua karakter atau, jika Elemen Teks diwakili oleh beberapa Poin Kode beberapa kombinasi karakter tunggal dan Pasangan Pengganti. Seolah-olah itu tidak cukup rumit, beberapa Elemen Teks dapat diwakili oleh berbagai kombinasi Poin Kode seperti yang dijelaskan dalam, Unicode Standard Annex # 15, FORMULIR NORMALISASI UNICODE .Selingan
Jadi, string yang terlihat sama ketika diberikan sebenarnya dapat terdiri dari kombinasi karakter yang berbeda. Suatu perbandingan ordinal (byte demi byte) dari dua string semacam itu akan mendeteksi perbedaan, ini mungkin tidak terduga atau tidak diinginkan.
Anda bisa menyandikan ulang string .Net. sehingga mereka menggunakan Formulir Normalisasi yang sama. Setelah dinormalisasi, dua string dengan Elemen Teks yang sama akan dikodekan dengan cara yang sama. Untuk melakukan ini, gunakan fungsi string . Normalisasi . Namun, ingat, beberapa Elemen Teks yang berbeda terlihat mirip satu sama lain. : -s
Jadi, apa artinya semua ini dalam kaitannya dengan pertanyaan? Elemen Teks
'𠈓'
diwakili oleh satu Code Point U + 20213 cjk unified ideaographs extension b . Ini berarti tidak dapat dikodekan sebagai tunggalchar
dan harus dikodekan sebagai Pasangan Pengganti, menggunakan dua karakter. Inilah sebabnya mengapastring b
satuchar
lagi itustring a
.Jika Anda perlu andal (lihat peringatan) hitung jumlah Elemen Teks dalam
string
Anda harus menggunakanSystem.Globalization.StringInfo
kelas seperti ini.memberikan output,
seperti yang diharapkan.
Peringatan
Implementasi .Net Segmentasi Teks Unicode di dalam
StringInfo
danTextElementEnumerator
kelas harus umumnya bermanfaat dan, dalam banyak kasus, akan menghasilkan respons yang diharapkan oleh penelepon. Namun, seperti yang dinyatakan dalam Unicode Standard Annex # 29, "Tujuan pencocokan persepsi pengguna tidak selalu dapat dipenuhi persis karena teks saja tidak selalu berisi informasi yang cukup untuk menentukan batas secara jelas."sumber