
Artikel ini mengeksplorasi konsep dasar di balik pengkodean karakter dan kemudian menyelam lebih dalam ke rincian teknis sistem pengkodean.
Jika Anda hanya memiliki pengetahuan dasar tentang pengkodean karakter dan ingin lebih memahami esensi, perbedaan antara sistem pengkodean, mengapa kita terkadang berakhir dengan teks yang tidak masuk akal, dan prinsip-prinsip di balik arsitektur sistem pengkodean yang berbeda, kemudian baca terus.
Untuk memahami pengkodean karakter secara detail membutuhkan beberapa bacaan yang luas dan banyak waktu. Saya telah mencoba untuk menyelamatkan Anda dari upaya itu dengan menyatukan semuanya di satu tempat sambil memberikan apa yang saya yakini sebagai latar belakang topik yang cukup menyeluruh.
Saya akan membahas bagaimana pengkodean byte tunggal (ASCII, Windows-1251 dll) bekerja, sejarah bagaimana Unicode menjadi, pengkodean berbasis Unicode UTF-8, UTF-16 dan bagaimana perbedaannya, fitur spesifik, kompatibilitas, dan ketiadaan di antara berbagai pengkodean, prinsip pengkodean karakter, dan panduan praktis tentang bagaimana karakter dikodekan dan didekodekan.
Meskipun pengodean karakter mungkin bukan topik yang canggih, penting untuk memahami cara kerjanya sekarang dan bagaimana cara kerjanya di masa lalu tanpa menghabiskan banyak waktu.
Sejarah unicode
Saya pikir yang terbaik adalah memulai cerita kami dari waktu ketika komputer berada di tempat yang tidak semaju atau biasa dalam kehidupan kita seperti sekarang. Pengembang dan insinyur yang mencoba untuk menghasilkan standar pada saat itu tidak tahu bahwa komputer dan internet akan sangat populer dan meresap seperti yang mereka lakukan. Ketika itu terjadi, dunia membutuhkan pengkodean karakter.
Tetapi bagaimana Anda bisa memiliki komputer menyimpan karakter atau huruf ketika hanya mengerti satu dan nol? Dari kebutuhan ini muncul pengkodean ASCII 1-byte pertama, yang walaupun belum tentu pengkodean pertama, adalah yang paling banyak digunakan dan menetapkan tolok ukur. Jadi ini standar yang baik untuk digunakan.
Tapi apa itu ASCII? Kode ASCII terdiri dari 8 bit. Beberapa aritmatika mudah menunjukkan bahwa rangkaian karakter ini berisi 256 simbol (delapan bit, nol dan yang 2βΈ = 256).
7-bit pertama - 128 simbol (2β· = 128) dalam himpunan digunakan untuk huruf Latin, karakter kontrol (seperti jeda garis keras, tab dan sebagainya) dan simbol gramatikal. Bit lainnya adalah untuk bahasa nasional. Dengan cara ini, 128 karakter pertama selalu sama, dan jika Anda ingin menyandikan bahasa asli Anda, bantu diri Anda dengan simbol yang tersisa.
Ini memunculkan banyak sekali pengkodean nasional. Anda berakhir dengan situasi seperti ini: misalkan Anda di Rusia membuat file teks yang secara default akan menggunakan Windows-1251 (pengodean Rusia yang digunakan di Windows). Dan Anda mengirim dokumen Anda ke seseorang di luar Rusia, katakanlah di AS. Bahkan jika penerima tahu bahasa Rusia, mereka akan kurang beruntung ketika mereka membuka dokumen di komputer mereka (dengan perangkat lunak pengolah kata menggunakan ASCII sebagai kode default) karena mereka akan melihat karakter kacau yang aneh (mojibake) alih-alih huruf Rusia. . Lebih tepatnya, setiap huruf bahasa Inggris akan muncul dengan baik, karena 128 simbol pertama di Windows-1251 dan ASCII adalah identik, tetapi di mana pun ada teks Rusia, perangkat lunak pengolah kata penerima kami akan menggunakan pengkodean yang salah kecuali jika pengguna telah secara manual menetapkan karakter yang tepat pengkodean.
Masalah dengan standar kode karakter nasional sudah jelas. Dan akhirnya, kode-kode nasional ini mulai berlipat ganda, internet mulai meledak, dan semua orang ingin menulis dalam bahasa nasionalnya tanpa membuat mojibake yang tidak dapat dipahami ini.
Ada dua opsi pada saat ini - gunakan pengkodean untuk setiap negara atau buat peta karakter universal untuk mewakili semua karakter di planet ini.
A Primer Pendek Pada ASCII
Ini mungkin terlihat terlalu dasar, tetapi jika kita harus teliti kita harus membahas semua pangkalan.

Ada 3 grup kolom dalam tabel ASCII:
- nilai desimal karakter
- nilai heksadesimal karakter
- mesin terbang untuk karakter itu sendiri
Katakanlah kita ingin menyandikan kata "ok" di ASCII. Huruf "o" memiliki nilai desimal 111 dan 6F dalam heksadesimal. Dalam biner, yaitu - 01101111. Huruf "k" adalah posisi 107 dalam desimal dan 6B dalam hex, atau - 01101011 dalam biner. Jadi kata "OK" di ASCII akan terlihat seperti 01101111 01101011. Proses decoding akan sebaliknya. Kita mulai dengan 8 bit, menerjemahkannya menjadi pengkodean desimal dan berakhir dengan nomor karakter, dan mencari tabel untuk simbol yang sesuai.
Unicode
Dari penjelasan di atas, seharusnya sudah cukup jelas mengapa diperlukan satu peta karakter umum. Tapi seperti apa bentuknya? Jawabannya adalah Unicode yang sebenarnya bukan encoding, tetapi set karakter. Terdiri dari 1.114.112 posisi, atau titik kode, yang sebagian besar masih kosong, jadi tidak mungkin set perlu diperluas.
Standar Unicode terdiri dari 17 pesawat dengan masing-masing 65.536 poin kode. Setiap bidang berisi sekelompok simbol. Pesawat nol adalah bidang multibahasa dasar di mana kami menemukan karakter yang paling umum digunakan dalam semua huruf modern. Pesawat kedua berisi karakter dari bahasa yang mati. Bahkan ada dua pesawat yang disediakan untuk penggunaan pribadi. Sebagian besar pesawat masih kosong.
Unicode memiliki poin kode untuk 0 hingga 10FFFF (dalam heksadesimal).
Karakter dikodekan dalam format heksadesimal yang diawali dengan "U +". Jadi, misalnya, bidang dasar pertama mencakup karakter U + 0000 ke U + FFFF (0 hingga 65.535), dan blok 17 berisi U + 100000 hingga U + 10FFFF (1.048.576 hingga 1.114.111).
Jadi sekarang alih-alih menagerie dari banyak pengkodean, kami memiliki tabel semua yang mencakup semua simbol dan karakter yang mungkin kita butuhkan. Tetapi ini bukan tanpa kesalahannya. Sementara setiap karakter sebelumnya dikodekan oleh satu byte, sekarang dapat dikodekan menggunakan jumlah byte yang berbeda. Misalnya, Anda hanya perlu satu byte untuk mengkodekan semua huruf dalam alfabet bahasa Inggris. Misalnya, huruf Latin "o" di Unicode adalah U + 006F. Dengan kata lain, angka yang sama dengan ASCII - 6F dalam heksadesimal dan 111 dalam biner. Tetapi untuk menyandikan simbol "U + 103D5" (angka Persia "100"), kita membutuhkan 103D5 dalam hex dan 66.517 dalam desimal, dan sekarang kita membutuhkan tiga byte.
Kompleksitas ini harus diatasi dengan pengkodean Unicode seperti UTF-8 dan UTF-16. Dan selanjutnya kita akan melihat mereka.
Utf-8
UTF-8 adalah pengkodean Unicode dari sistem pengodean lebar variabel yang dapat digunakan untuk menampilkan simbol Unicode.
Apa yang kita maksudkan ketika berbicara tentang lebar variabel? Pertama-tama, kita perlu memahami bahwa unit struktural (atom) dalam pengkodean adalah byte. Pengodean lebar variabel berarti satu karakter dapat dikodekan menggunakan jumlah unit atau byte yang berbeda. Misalnya, huruf Latin dikodekan dengan satu byte, dan huruf Cyrillic dengan dua.
Sebelum kita melanjutkan, sedikit menyinggung tentang kompatibilitas antara ASCII dan UTF.
Fakta bahwa huruf Latin dan karakter kontrol kunci seperti jeda baris, tab berhenti, dll. berisi satu byte membuat pengkodean-UTF kompatibel dengan ASCII. Dengan kata lain, skrip Latin dan karakter kontrol ditemukan dalam titik kode yang sama persis di ASCII dan UTF dan dikodekan menggunakan satu byte di keduanya, dan karenanya kompatibel ke belakang.
Mari kita gunakan huruf "o" dari contoh ASCII kami sebelumnya. Ingatlah bahwa posisinya dalam tabel ASCII adalah 111, atau 01101111 dalam biner. Dalam tabel Unicode, ini adalah U + 006F, atau 01101111. Dan sekarang karena UTF adalah sistem pengkodean dengan lebar variabel βoβ akan menjadi satu byte. Dengan kata lain, "o" akan diwakili dengan cara yang sama di keduanya. Dan hal yang sama untuk karakter 0 - 128. Jadi, jika dokumen Anda berisi huruf-huruf bahasa Inggris Anda tidak akan melihat perbedaan jika Anda membukanya menggunakan UTF-8, UTF-16, atau ASCII, dan hanya akan melihat perbedaan jika Anda mulai bekerja dengan pengkodean nasional.
Mari kita lihat bagaimana ungkapan bahasa Inggris / Rusia βHello Worldβ akan muncul dalam tiga sistem pengkodean yang berbeda: Windows-1251 (pengodean Rusia), ISO-8859-1 (sistem pengodean untuk bahasa Eropa Barat), UTF-8 (Unicode) . Contoh ini memberi tahu karena kami memiliki frasa dalam dua bahasa yang berbeda.

Sekarang mari kita pertimbangkan bagaimana sistem pengkodean ini bekerja dan bagaimana kita dapat menerjemahkan satu baris teks dari satu pengkodean ke yang lain, dan apa yang terjadi jika karakter ditampilkan dengan tidak tepat, atau jika kita tidak dapat melakukan ini karena perbedaan dalam sistem.
Mari kita asumsikan bahwa frasa asli kami ditulis dengan penyandian Windows-1251. Ketika kita melihat tabel di atas kita bisa melihat dengan menerjemahkan dari desimal atau hex ke desimal bahwa kita mendapatkan pengkodean di bawah dalam biner menggunakan Windows-1251.
01001000 01100101 01101100 01101100 01101111 00100000 11101100 11101000 11110000
Jadi sekarang kita memiliki frasa "Hello World" di Windows-1251 encoding.
Sekarang bayangkan bahwa kita memiliki file teks tetapi kita tidak tahu sistem pengkodean teks yang menyimpannya. Kami menganggap itu disandikan dalam ISO-8859-1 dan membukanya di pengolah kata kami menggunakan sistem penyandian ini. Seperti yang kita lihat sebelumnya, beberapa karakter tampak baik-baik saja, seperti yang ada di sistem pengkodean ini, dan bahkan ada di titik kode yang sama, tetapi karakter dalam kata Rusia "dunia" tidak bekerja dengan baik juga. Karakter-karakter ini tidak ada dalam sistem pengkodean, dan di tempat mereka, atau titik kode, di ISO-8859-1 kami menemukan karakter yang sama sekali berbeda. Jadi "m" adalah titik kode 236, "dan" adalah 232, dan "p" adalah 240. Tetapi dalam ISO-8859-1 titik kode ini sesuai dengan "Γ¬" (236), "Γ¨" (232), dan " Γ° β(240).
Jadi, frasa bahasa campuran kami "Hello World" yang disandikan di Windows-1251 dan dibaca di ISO-8859-1 akan terlihat seperti "Hello ìèð". Kami memiliki kompatibilitas sebagian dan kami tidak dapat menampilkan frasa yang dikodekan dalam satu sistem dengan benar di sistem lain, karena simbol yang kami butuhkan tidak ada dalam pengkodean kedua.
Kami membutuhkan pengkodean Unicode - dalam kasus kami, kami akan menggunakan UTF-8 sebagai contoh. Kita telah membahas bahwa karakter dapat mengambil antara 1 hingga 4 byte di UTF-8, tetapi keuntungan lain adalah bahwa UTF, tidak seperti dua sistem pengkodean sebelumnya, tidak dibatasi hingga 256 simbol, tetapi berisi semua simbol dalam rangkaian karakter Unicode .
Ia bekerja seperti ini: bit pertama dari setiap karakter yang dikodekan tidak sesuai dengan mesin terbang atau simbol itu sendiri, tetapi dengan byte tertentu. Jadi, jika bit pertama adalah nol, kita tahu bahwa simbol yang dikodekan hanya menggunakan satu byte - yang membuat set kompatibel dengan ASCII. Jika kita melihat lebih dekat pada tabel simbol ASCII kita melihat bahwa 128 simbol pertama (alfabet Inggris, karakter kontrol, dan tanda baca) dinyatakan dalam biner, semuanya dimulai dengan nilai bit 0 (perhatikan bahwa jika Anda menerjemahkan karakter ke dalam biner menggunakan konverter online atau yang serupa bit nol orde tinggi pertama dapat dibuang, yang dapat sedikit membingungkan).
01001000 - nilai bit pertama adalah 0, jadi 1 byte mengkodekan 1 karakter -> "H".
01100101 - nilai bit pertama adalah 0, jadi 1 byte mengkodekan 1 karakter-> "e".
Jika nilai bit pertama bukan nol, simbol akan dikodekan dalam beberapa byte.
Pengkodean dua byte akan memiliki 110 untuk tiga nilai bit pertama.
11010000 10111100 - bit penanda adalah 110 dan 10, jadi kami menggunakan 2 byte untuk menyandikan 1 karakter. Byte kedua dalam kasus ini selalu dimulai dengan "10." Jadi kami menghilangkan bit kontrol (bit utama yang disorot dalam warna merah dan hijau) dan melihat sisa kode (10000111100), dan mengkonversi ke hex (043) -> U + 043C yang memberi kita "m" dalam bahasa Unicode.
Bit awal untuk karakter tiga byte adalah 1110.
11101000 10000111 101010101 - kami menjumlahkan semua bit kecuali bit kontrol dan kami menemukan bahwa dalam hex kami memiliki 103B5, U + 103D5 - nomor Persia kuno seratus (10000001111010101).
Pengkodean karakter empat byte dimulai dengan bit-bit memimpin 11110.
11110100 10001111 10111111 10111111 - U + 10FFFF yang merupakan karakter terakhir yang tersedia di set Unicode (1000011111111111111111111).
Sekarang, kita dapat dengan mudah menulis frase multi-bahasa dalam pengkodean UTF-8.
Utf-16
UTF-16 adalah pengodean lebar variabel lainnya. Perbedaan utama antara UTF-16 dan UTF-8 adalah bahwa UTF-16 menggunakan 2 byte (16 bit) per unit kode alih-alih 1 bye (8 bit). Dengan kata lain, setiap karakter Unicode yang dikodekan dalam UTF-16 dapat berupa dua atau empat byte. Untuk menjaga hal-hal sederhana, saya akan merujuk pada dua byte ini sebagai unit kode. Jadi, dalam UTF-16 karakter apa pun dapat direpresentasikan menggunakan salah satu atau dua unit kode.
Mari kita mulai dengan simbol yang dikodekan menggunakan satu unit kode. Kita dapat dengan mudah menghitung bahwa ada 65.535 (216) karakter dengan satu unit kode, yang sejajar dengan bidang multibahasa dasar Unicode. Semua karakter di pesawat ini akan diwakili oleh satu unit kode (dua byte) di UTF-16.
Huruf latin "o" - 00000000 01101111.
Huruf Cyrillic "M" - 00000100 00011100.
Sekarang mari kita pertimbangkan karakter di luar bidang multibahasa dasar. Ini membutuhkan dua unit kode (4 byte) dan dikodekan dengan cara yang sedikit lebih rumit.
Pertama, kita perlu mendefinisikan konsep pasangan pengganti. Pasangan pengganti adalah dua unit kode yang digunakan untuk menyandikan satu karakter (total 4 byte). Set karakter Unicode menyimpan kisaran khusus D800 ke DFFF untuk pasangan pengganti. Ini berarti bahwa ketika mengonversi pasangan pengganti menjadi byte dalam heksadesimal, kita berakhir dengan titik kode dalam rentang ini yang merupakan pasangan pengganti daripada karakter yang terpisah.
Untuk menyandikan simbol dalam rentang 10000 - 10FFFF (mis., Karakter yang memerlukan lebih dari satu unit kode) kami memproses sebagai berikut:
Kurangi 10.000 (hex) dari titik kode (ini adalah titik kode terendah di kisaran 10.000 - 10FFFF).
Kami berakhir dengan angka 20-bit tidak lebih besar dari FFFF.
10 bit orde tinggi yang akhirnya kita tambahkan ke D800 (titik kode terendah dalam kisaran pasangan pengganti di Unicode).
10 bit berikutnya ditambahkan ke DC00 (juga dari kisaran pasangan pengganti).
Selanjutnya, kita berakhir dengan 2 unit kode 16-bit pengganti, 6 bit pertama yang mendefinisikan unit sebagai bagian dari pasangan pengganti.
Bit kesepuluh di setiap pengganti mendefinisikan urutan pasangan. Jika kita memiliki "1" itu adalah pengganti atau yang tinggi, dan jika kita memiliki "0" itu adalah pengganti atau rendah pengganti.
Ini akan lebih masuk akal ketika diilustrasikan dengan contoh di bawah ini.
Mari kita encode dan kemudian decode angka Persia seratus (U + 103D5):
103D5 - 10.000 = 3D5.
3D5 = 0000000000 1111010101 (10 bit tinggi adalah nol, dan ketika dikonversi ke heksadesimal kita berakhir dengan "0" (sepuluh yang pertama), dan 3D5 (sepuluh yang kedua)).
0 + D800 = D800 (1101100000000000) 6 bit pertama memberitahu kita bahwa titik kode ini jatuh dalam kisaran pasangan pengganti, bit kesepuluh (dari kanan) memiliki nilai "0", jadi ini adalah pengganti tinggi.
3D5 + DC00 = DFD5 (1101111111010101) 6 bit pertama memberi tahu kami bahwa titik kode ini jatuh dalam kisaran pasangan pengganti, bit kesepuluh (dari kanan) adalah "1", jadi kami tahu ini adalah pengganti rendah.
Karakter yang dihasilkan dikodekan dalam UTF-16 terlihat seperti - 1101100000000000 1101111111010101.
Sekarang mari kita decode karakternya. Katakanlah kita memiliki titik kode berikut - 1101100000100010 1101111010001000:
Kami mengonversi ke heksadesimal = D822 DE88 (kedua titik kode berada dalam kisaran pasangan pengganti, jadi kami tahu bahwa kami sedang berurusan dengan pasangan pengganti).
1101100000100010 - bit kesepuluh (dari kanan) adalah "0", jadi ini adalah pengganti tinggi.
1101111010001000 - bit kesepuluh (dari kanan) adalah "1", jadi ini adalah pengganti rendah.
Kami mengabaikan 6 bit yang mengidentifikasi ini sebagai pengganti dan dibiarkan dengan 0000100010 1010001000 (8A88).
Kami menambahkan 10.000 (titik kode terendah dalam kisaran pengganti) 8A88 + 10000 = 18A88.
Kami melihat tabel Unicode untuk U + 18A88 = Tangut Component-649.
Kudos untuk semua orang yang membaca sejauh ini!
Saya harap ini informatif tanpa membuat Anda bosan.
Anda mungkin juga menemukan berguna:
Set karakter unicode
Strategi untuk pelokalan konten: berbasis IP atau browser
Tentang penerjemah
Alconost adalah penyedia global layanan pelokalan untuk aplikasi , game , video, dan situs web dalam 70+ bahasa. Kami menawarkan terjemahan oleh ahli bahasa penutur asli, pengujian linguistik, alur kerja berbasis cloud, pelokalan berkelanjutan, manajemen proyek 24/7, dan bekerja dengan format sumber daya string apa pun. Kami juga membuat video dan gambar iklan dan pendidikan, permainan asah, penjelas, dan trailer untuk Google Play dan App Store.