Kunci utama untuk masalah encoding tersebut adalah untuk memahami bahwa pada prinsipnya ada dua konsep berbeda dari "string" : (1) string karakter , dan (2) string / array byte. Perbedaan ini sebagian besar telah diabaikan untuk waktu yang lama karena penyandian di mana-mana yang bersejarah dengan tidak lebih dari 256 karakter (ASCII, Latin-1, Windows-1252, Mac OS Roman,…): pengkodean ini memetakan sekumpulan karakter umum ke angka antara 0 dan 255 (yaitu byte); pertukaran file yang relatif terbatas sebelum munculnya web membuat situasi penyandian yang tidak kompatibel ini dapat ditoleransi, karena sebagian besar program dapat mengabaikan fakta bahwa ada beberapa penyandiaksaraan selama mereka menghasilkan teks yang tetap pada sistem operasi yang sama: program semacam itu hanya akan perlakukan teks sebagai byte (melalui pengkodean yang digunakan oleh sistem operasi). Tampilan modern yang benar memisahkan kedua konsep string ini dengan tepat, berdasarkan dua poin berikut:
Karakter sebagian besar tidak terkait dengan komputer : seseorang dapat menggambarnya di papan kapur, dll., Seperti misalnya بايثون, 中 蟒 dan 🐍. "Karakter" untuk mesin juga mencakup "instruksi menggambar" seperti misalnya spasi, carriage return, instruksi untuk mengatur arah penulisan (untuk bahasa Arab, dll.), Aksen, dll. Daftar karakter yang sangat besar disertakan dalam standar Unicode ; itu mencakup sebagian besar karakter yang dikenal.
Di sisi lain, komputer memang perlu merepresentasikan karakter abstrak dengan beberapa cara: untuk ini, mereka menggunakan array byte (termasuk angka antara 0 dan 255), karena memori mereka datang dalam potongan byte. Proses yang diperlukan untuk mengubah karakter menjadi byte disebut pengkodean . Jadi, komputer membutuhkan pengkodean untuk mewakili karakter. Teks apa pun yang ada di komputer Anda dikodekan (hingga ditampilkan), apakah itu dikirim ke terminal (yang mengharapkan karakter dikodekan dengan cara tertentu), atau disimpan dalam file. Agar dapat ditampilkan atau "dipahami" dengan benar (oleh, katakanlah, penerjemah Python), aliran byte didekodekan menjadi karakter. Beberapa pengkodean(UTF-8, UTF-16,…) didefinisikan oleh Unicode untuk daftar karakternya (Unicode mendefinisikan kedua daftar karakter dan pengkodean untuk karakter ini — masih ada tempat di mana seseorang melihat ekspresi "Unicode encoding" sebagai cara untuk merujuk ke UTF-8 di mana-mana, tetapi ini adalah terminologi yang salah, karena Unicode menyediakan banyak pengkodean).
Singkatnya, komputer perlu merepresentasikan karakter secara internal dengan byte , dan mereka melakukannya melalui dua operasi:
Pengkodean : karakter → byte
Decoding : byte → karakter
Beberapa pengkodean tidak dapat mengkodekan semua karakter (misalnya, ASCII), sementara (beberapa) pengkodean Unicode memungkinkan Anda untuk mengenkode semua karakter Unicode. Pengkodean juga belum tentu unik , karena beberapa karakter dapat direpresentasikan baik secara langsung atau sebagai kombinasi (misalnya, karakter dasar dan aksen).
Perhatikan bahwa konsep baris baru menambahkan lapisan kerumitan , karena dapat diwakili oleh karakter (kontrol) berbeda yang bergantung pada sistem operasi (ini adalah alasan mode membaca file baris baru universal Python ).
Sekarang, apa yang saya sebut "karakter" di atas adalah apa yang disebut Unicode sebagai " karakter yang dipersepsi pengguna ". Karakter tunggal yang dirasakan pengguna terkadang dapat direpresentasikan dalam Unicode dengan menggabungkan bagian karakter (karakter dasar, aksen,…) yang ditemukan di indeks berbeda dalam daftar Unicode, yang disebut " poin kode " —poin kode ini dapat digabungkan bersama untuk membentuk sebuah "cluster grafem". Unicode dengan demikian mengarah ke konsep string ketiga, yang dibuat dari urutan poin kode Unicode, yang berada di antara byte dan string karakter, dan yang lebih dekat dengan yang terakhir. Saya akan menyebutnya " string Unicode " (seperti di Python 2).
Sementara Python dapat mencetak string karakter (yang dirasakan pengguna), string non-byte Python pada dasarnya adalah urutan poin kode Unicode , bukan karakter yang dipersepsi pengguna. Nilai titik kode adalah yang digunakan dalam sintaks string Python \u
dan \U
Unicode. Mereka tidak boleh bingung dengan pengkodean karakter (dan tidak harus memiliki hubungan apa pun dengannya: Titik kode Unicode dapat dikodekan dengan berbagai cara).
Ini memiliki konsekuensi penting: panjang string Python (Unicode) adalah jumlah poin kodenya, yang tidak selalu jumlah karakter yang dirasakan pengguna : jadi s = "\u1100\u1161\u11a8"; print(s, "len", len(s))
(Python 3) memberi 각 len 3
meskipun s
memiliki satu yang dirasakan pengguna (Korea) karakter (karena diwakili dengan 3 titik kode — meskipun tidak harus, seperti yang print("\uac01")
ditunjukkan). Namun, dalam banyak keadaan praktis, panjang string adalah jumlah karakter yang dianggap pengguna, karena banyak karakter biasanya disimpan oleh Python sebagai titik kode Unicode tunggal.
Dalam Python 2 , string Unicode disebut… "Unicode strings" ( unicode
tipe, bentuk literal u"…"
), sedangkan array byte adalah "string" ( str
jenis, di mana array byte dapat misalnya dibangun dengan string literal "…"
). Dalam Python 3 , string Unicode disebut "string" ( str
tipe, bentuk literal "…"
), sedangkan array byte disebut "byte" ( bytes
tipe, bentuk literal b"…"
). Akibatnya, sesuatu seperti "🐍"[0]
memberikan hasil yang berbeda dalam Python 2 ( '\xf0'
, byte) dan Python 3 ( "🐍"
, karakter pertama dan satu-satunya).
Dengan beberapa poin kunci ini, Anda seharusnya dapat memahami sebagian besar pertanyaan terkait pengkodean!
Biasanya, saat Anda mencetak u"…"
ke terminal , Anda tidak akan mendapatkan sampah: Python mengetahui pengkodean terminal Anda. Nyatanya, Anda dapat memeriksa pengkodean apa yang diharapkan terminal:
% python
Python 2.7.6 (default, Nov 15 2013, 15:20:37)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.stdout.encoding
UTF-8
Jika karakter input Anda dapat dikodekan dengan pengkodean terminal, Python akan melakukannya dan akan mengirimkan byte yang sesuai ke terminal Anda tanpa mengeluh. Terminal kemudian akan melakukan yang terbaik untuk menampilkan karakter setelah mendekode byte input (paling buruk font terminal tidak memiliki beberapa karakter dan sebaliknya akan mencetak beberapa jenis kosong).
Jika karakter input Anda tidak dapat dikodekan dengan pengkodean terminal, itu berarti terminal tidak dikonfigurasi untuk menampilkan karakter ini. Python akan mengeluh (dalam Python dengan a UnicodeEncodeError
karena string karakter tidak dapat dikodekan dengan cara yang sesuai dengan terminal Anda). Satu-satunya solusi yang mungkin adalah menggunakan terminal yang dapat menampilkan karakter (baik dengan mengkonfigurasi terminal sehingga menerima pengkodean yang dapat mewakili karakter Anda, atau dengan menggunakan program terminal yang berbeda). Ini penting ketika Anda mendistribusikan program yang dapat digunakan di lingkungan yang berbeda: pesan yang Anda cetak harus dapat diwakili di terminal pengguna. Terkadang yang terbaik adalah tetap menggunakan string yang hanya berisi karakter ASCII.
Namun, ketika Anda mengalihkan atau menyalurkan output dari program Anda, maka umumnya tidak mungkin untuk mengetahui apa pengkodean input dari program penerima, dan kode di atas mengembalikan beberapa pengkodean default: Tidak Ada (Python 2.7) atau UTF-8 ( Python 3):
% python2.7 -c "import sys; print sys.stdout.encoding" | cat
None
% python3.4 -c "import sys; print(sys.stdout.encoding)" | cat
UTF-8
Pengkodean stdin, stdout dan stderr dapat diatur melalui PYTHONIOENCODING
variabel lingkungan, jika diperlukan:
% PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | cat
UTF-8
Jika pencetakan ke terminal tidak menghasilkan apa yang Anda harapkan, Anda dapat memeriksa apakah pengkodean UTF-8 yang Anda masukkan secara manual sudah benar; misalnya, karakter pertama Anda ( \u001A
) tidak dapat dicetak, jika saya tidak salah .
Di http://wiki.python.org/moin/PrintFails , Anda dapat menemukan solusi seperti berikut, untuk Python 2.x:
import codecs
import locale
import sys
# Wrap sys.stdout into a StreamWriter to allow writing unicode.
sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni
Untuk Python 3, Anda dapat memeriksa salah satu pertanyaan yang ditanyakan sebelumnya di StackOverflow.