Bu tür kodlama problemlerinin bütün anahtarı, prensipte iki farklı "dizge" kavramının olduğunu anlamaktır : (1) karakter dizesi ve (2) dizge / bayt dizisi. 256 karakterden fazla olmayan kodlamaların tarihsel olarak her yerde bulunması nedeniyle (ASCII, Latin-1, Windows-1252, Mac OS Roman,…) bu ayrım çoğunlukla uzun zamandır göz ardı edilmiştir: bu kodlamalar, bir dizi ortak karakteri eşleştirir. 0 ile 255 arasındaki sayılar (yani bayt); Web'in gelişinden önce nispeten sınırlı dosya değişimi, bu uyumsuz kodlama durumunu tolere edilebilir hale getirdi, çünkü çoğu program, aynı işletim sisteminde kalan metin ürettikleri sürece birden fazla kodlama olduğu gerçeğini görmezden gelebilirdi: bu tür programlar basitçe metni bayt olarak ele alın (işletim sistemi tarafından kullanılan kodlama yoluyla). Doğru, modern görünüm, aşağıdaki iki noktaya göre bu iki dizi kavramını doğru bir şekilde ayırır:
Karakterler çoğunlukla bilgisayarlarla ilgisizdir : örneğin بايثون, 中 蟒 ve 🐍 gibi bir kişi onları tebeşir tahtasına vb. Çizebilir. Makineler için "karakterler" ayrıca boşluklar, satır başı, yazma yönünü belirleme talimatları (Arapça vb. İçin), aksanlar vb. Gibi "çizim talimatlarını" da içerir . Unicode standardında çok büyük bir karakter listesi bulunur ; bilinen karakterlerin çoğunu kapsar.
Öte yandan, bilgisayarların bir şekilde soyut karakterleri temsil etmesi gerekir: bunun için bayt dizilerini kullanırlar (0 ile 255 arasında sayılar dahil), çünkü bellekleri bayt yığınları halinde gelir. Karakterleri bayta dönüştüren gerekli işleme kodlama denir . Bu nedenle, bir bilgisayar , karakterleri temsil etmek için bir kodlama gerektirir . Bilgisayarınızda bulunan herhangi bir metin, ister bir terminale (belirli bir şekilde kodlanmış karakterleri bekleyen) gönderilsin veya bir dosyaya kaydedilsin (görüntülenene kadar) kodlanır. Görüntülenmek veya düzgün bir şekilde "anlaşılmak" için (örneğin Python yorumlayıcısı tarafından), bayt akışlarının kodu karakterlere dönüştürülür. Birkaç kodlama(UTF-8, UTF-16,…) Unicode tarafından karakter listesi için tanımlanır (böylece Unicode hem karakterlerin bir listesini hem de bu karakterler için kodlamaları tanımlar — "Unicode kodlaması" ifadesinin bir her yerde bulunan UTF-8'e başvurmanın yolu, ancak Unicode birden çok kodlama sağladığından bu yanlış terminolojidir ).
Özetle, bilgisayarların karakterleri baytlarla dahili olarak temsil etmesi gerekir ve bunu iki işlemle yaparlar:
Kodlama : karakterler → bayt
Kod çözme : bayt → karakterler
Bazı kodlamalar tüm karakterleri (örneğin, ASCII) kodlayamazken (bazıları) Unicode kodlamaları tüm Unicode karakterlerini kodlamanıza izin verir. Kodlamanın da benzersiz olması gerekmez , çünkü bazı karakterler ya doğrudan ya da bir kombinasyon (örneğin bir temel karakter ve aksan) olarak temsil edilebilir.
Satırsonu kavramının bir karmaşıklık katmanı eklediğine dikkat edin , çünkü işletim sistemine bağlı olan farklı (kontrol) karakterlerle temsil edilebilir (bu, Python'un evrensel satırsonu dosyası okuma modunun nedenidir ).
Şimdi, yukarıda "karakter" olarak adlandırdığım şey, Unicode'un " kullanıcı tarafından algılanan karakter " olarak adlandırdığı şeydir . Kullanıcı tarafından algılanan tek bir karakter, bazen Unicode listesindeki farklı dizinlerde bulunan ve " kod noktaları " olarak adlandırılan karakter parçalarını (temel karakter, aksanlar, ...) birleştirerek Unicode'da temsil edilebilir - bu kod noktaları, oluşturmak için bir araya getirilebilir bir "grafem kümesi". Böylelikle Unicode, bayt ve karakter dizileri arasında yer alan ve sonuncusuna daha yakın olan bir Unicode kod noktası dizisinden oluşan üçüncü bir dizi kavramına yol açar. Bunlara " Unicode dizeleri " adını vereceğim (Python 2'deki gibi).
Python, (kullanıcı tarafından algılanan) karakter dizilerini yazdırabilirken , Python bayt olmayan dizeler aslında kullanıcı tarafından algılanan karakterlerin değil, Unicode kod noktalarının dizileridir . Kod noktası değerleri Python'un \u
ve \U
Unicode dizgi sözdiziminde kullanılan değerlerdir . Bir karakterin kodlamasıyla karıştırılmamalıdırlar (ve onunla herhangi bir ilişkisi olması gerekmez: Unicode kod noktaları çeşitli şekillerde kodlanabilir).
Bunun önemli bir sonucu vardır: Bir Python (Unicode) dizesinin uzunluğu kod noktalarının sayısıdır ve bu her zaman kullanıcı tarafından algılanan karakter sayısı değildir : bu nedenle s = "\u1100\u1161\u11a8"; print(s, "len", len(s))
(Python 3), tek bir kullanıcı tarafından algılanmasına 각 len 3
rağmen s
(Korece) verir karakter (çünkü 3 kod noktasıyla temsil edilir - gösterilmesi gerekmese bile print("\uac01")
). Bununla birlikte, birçok pratik durumda, bir dizenin uzunluğu, kullanıcı tarafından algılanan karakterlerin sayısıdır, çünkü birçok karakter tipik olarak Python tarafından tek bir Unicode kod noktası olarak saklanır.
In Python 2 Unicode dizeleri "Unicode dizeleri" (... denir unicode
tipi, edebi biçim u"…"
bayt dizileri "dizeleri" (iken) str
bayt dizisi örneği için dize hazır ile inşa edilebilir tip "…"
). In Python 3 Unicode dizeleri basitçe "dizeleri" (denir str
tipi, edebi biçim "…"
bayt dizileri "bayt" (iken) bytes
tipi, edebi biçim b"…"
). Sonuç "🐍"[0]
olarak, Python 2 ( '\xf0'
bayt) ve Python 3 ( "🐍"
ilk ve tek karakter) gibi bir şey farklı bir sonuç verir .
Bu birkaç anahtar nokta ile kodlamayla ilgili çoğu soruyu anlayabilirsiniz!
Normalde, bir terminale yazdırdığınızda , çöp almamalısınız: Python, terminalinizin kodlamasını bilir. Aslında, terminalin hangi kodlamayı beklediğini kontrol edebilirsiniz:u"…"
% 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
Giriş karakterleriniz terminalin kodlamasıyla kodlanabiliyorsa, Python bunu yapacak ve karşılık gelen baytları şikayet etmeden terminalinize gönderecektir. Uçbirim, girdi baytlarının kodunu çözdükten sonra karakterleri görüntülemek için elinden gelenin en iyisini yapacaktır (en kötü durumda uçbirim yazı tipi bazı karakterlere sahip değildir ve bunun yerine bir tür boş yazacaktır).
Giriş karakterleriniz terminalin kodlamasıyla kodlanamıyorsa, bu, terminalin bu karakterleri görüntülemek için yapılandırılmadığı anlamına gelir. Python şikayet edecek (Python'da a ile UnicodeEncodeError
karakter dizisi terminalinize uygun bir şekilde kodlanamaz). Olası tek çözüm, karakterleri görüntüleyebilen bir uçbirim kullanmaktır (uçbirimi, karakterlerinizi temsil edebilecek bir kodlamayı kabul edecek şekilde yapılandırarak veya farklı bir uçbirim programı kullanarak). Farklı ortamlarda kullanılabilen programları dağıtırken bu önemlidir: yazdırdığınız mesajlar kullanıcının terminalinde gösterilebilir olmalıdır. Bu nedenle bazen, yalnızca ASCII karakterleri içeren dizelere bağlı kalmak en iyisidir.
Ancak, programınızın çıktısını yeniden yönlendirdiğinizde veya yönlendirdiğinizde , alıcı programın giriş kodlamasının ne olduğunu bilmek genellikle mümkün değildir ve yukarıdaki kod bazı varsayılan kodlamaları döndürür: Yok (Python 2.7) veya 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
Bununla birlikte, stdin, stdout ve stderr kodlaması , gerekirse ortam değişkeni aracılığıyla ayarlanabilirPYTHONIOENCODING
:
% PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | cat
UTF-8
Bir terminale yazdırma beklediğinizi üretmiyorsa, manuel olarak yerleştirdiğiniz UTF-8 kodlamasının doğru olup olmadığını kontrol edebilirsiniz; örneğin, yanılmıyorsam ilk karakteriniz ( \u001A
) yazdırılamaz .
At http://wiki.python.org/moin/PrintFails , Python 2.x için aşağıdaki gibi bir çözüm bulabiliriz:
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
Python 3 için, daha önce StackOverflow'da sorulan sorulardan birini kontrol edebilirsiniz .