Python str ve unicode türleri


103

Python 2.7 ile çalışırken , her ikisi de Unicode dizelerini tutabilecek gibi göründüğü için türü unicodekullanmak yerine kullanmanın gerçek bir avantajı olduğunu merak ediyorum str. Ayrı Unicode kodları ayarlamak mümkün olmaktan özel bir nedeni var mı unicodekaçış kömürü kullanarak dizeleri \:

Bir modülü şu şekilde yürütmek:

# -*- coding: utf-8 -*-

a = 'á'
ua = u'á'
print a, ua

Sonuçlar: á, á

DÜZENLE:

Python kabuğu kullanarak daha fazla test:

>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'

Öyleyse, unicodedize latin1yerine kullanılarak kodlanmış gibi görünüyor utf-8ve ham dizge utf-8? Şimdi kafam daha da karıştı! : S


Hiçbir var kodlama için unicodeo unicode karakter sadece bir soyutlama var; bazı kodlamalarla unicodedönüştürülebilir str(örneğin utf-8).
Bin

Yanıtlar:


179

unicodemetni işlemek içindir . Metin dizisidir kod noktaları tek bir bayt daha büyük olabilir . Metin , metni ham baytlar (örn. , ...) olarak göstermek için belirli bir kodlamayla kodlanabilir .utf-8latin-1

Not unicode kodlanmış değil ! Python tarafından kullanılan dahili temsil bir uygulama detayıdır ve istediğiniz kod noktalarını temsil edebildiği sürece onu önemsememelisiniz.

strPython 2'de ise tam tersine düz bir bayt dizisidir . Metni temsil etmez!

unicodeBazı metinlerin genel bir temsili olarak düşünebilirsiniz , bunlar birçok farklı yolla, aracılığıyla temsil edilen bir ikili veri dizisine kodlanabilir str.

Not: Python 3'te, unicodeolarak yeniden adlandırılmıştır strve bytesdüz bir bayt dizisi için yeni bir tür vardır .

Görebileceğiniz bazı farklılıklar:

>>> len(u'à')  # a single code point
1
>>> len('à')   # by default utf-8 -> takes two bytes
2
>>> len(u'à'.encode('utf-8'))
2
>>> len(u'à'.encode('latin1'))  # in latin1 it takes one byte
1
>>> print u'à'.encode('utf-8')  # terminal encoding is utf-8
à
>>> print u'à'.encode('latin1') # it cannot understand the latin1 byte

Kullanmanın str, belirli bir kodlama gösteriminin tek baytları üzerinde daha düşük düzeyde bir denetime sahip olduğunuzu , kullanırken unicodeyalnızca kod noktası düzeyinde denetleyebileceğinizi unutmayın. Örneğin şunları yapabilirsiniz:

>>> 'àèìòù'
'\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'
>>> print 'àèìòù'.replace('\xa8', '')
à�ìòù

Daha önce geçerli olan UTF-8 artık değil. Unicode dizesi kullanarak, ortaya çıkan dizenin geçerli bir unicode metin olmayacağı şekilde işlem yapamazsınız. Bir kod noktasını kaldırabilir, bir kod noktasını farklı bir kod noktasıyla vb. Değiştirebilirsiniz, ancak dahili gösterimi bozamazsınız.


4
Cevabınız için çok teşekkürler, çok yardımcı oldu! Benim için en açıklayıcı kısım şudur: "unicode kodlanmamıştır! Python tarafından kullanılan dahili temsil bir uygulama detayıdır ve onu önemsememelisiniz [...]". Bu yüzden, unicodenesneleri serileştirirken encode(), unicodedeğeri temsil etmek için hangisinin dahili olarak kullanıldığını bilmediğimizden, ilk önce onları açıkça uygun kodlama formatına getirmemiz gerektiğini tahmin ediyorum .
Caumons

10
Evet. Bir metni (örneğin bir dosyaya) kaydetmek istediğinizde, onu baytlarla temsil etmelisiniz, yani onu kodlamalısınız . İçeriği alırken, baytların kodunu bir unicodenesneye dönüştürebilmek için kullanılan kodlamayı bilmeniz gerekir .
Bakuriu

Üzgünüm ama unicodeşifrelenmemiş ifade tamamen yanlış. UTF-16 / UCS-2 ve UTF-32 / UCS-4 de kodlamalardır ... ve gelecekte bunların daha fazlası muhtemelen oluşturulacaktır. Mesele şu ki, uygulama detayını önemsememeniz gerektiği için (ve aslında, yapmamalısınız!), Yine unicodede bunun kodlanmadığı anlamına gelmez . Tabii ki öyle. Olabilir mi, .decode()tamamen farklı bir hikaye.
0xC0000022L

1
@ 0xC0000022L Belki cümle olduğu gibi belirsizdir. Şunu söylemelidir: unicodenesne iç temsili, standart olmayan da dahil olmak üzere istediği her şey olabilir. Özellikle python3 + unicode , içerdiği verilere bağlı olarak değişen standart dışı bir dahili temsil kullanır. Bu nedenle, standart bir kodlama değildir . Bir metin standart sadece tanımlayan Unicode olarak codepoints bir olan soyut temsil metnin, standart utf-X vs Python verimlilik için kendi yolunu kullanır dahil bellekte kodlamak unicode yolunda tonlarca vardır.
Bakuriu

1
UTF-16 bir kodlama vardır olmasından Ayrıca 0xC0000022L @ şey CPython en ilgisi unicodeo zamandan beri, nesne değil UTF-16, ne de UTF-32 kullanın. Geçici bir temsil kullanır ve verileri gerçek baytlara kodlamak istiyorsanız kullanmanız gerekir encode. Ayrıca: dil, nasıl unicodeuygulanacağını zorunlu kılmaz , bu nedenle python'un farklı sürümleri veya uygulamaları farklı iç temsillere sahip olabilir (ve sahip olabilir ).
Bakuriu

38

Unicode ve kodlamalar tamamen farklı, ilgisiz şeylerdir.

Unicode

Her karaktere sayısal bir kimlik atar:

  • 0x41 → A
  • 0xE1 → á
  • 0x414 → Ä

Bu nedenle, Unicode 0x41 sayısını A'ya, 0xE1'i á'ya ve 0x414'ü Д'ye atar.

Kullandığım küçük ok bile Unicode numarasına sahip, 0x2192. Ve emojilerin bile kendi Unicode numaraları vardır, 😂 0x1F602'dir.

Bu tablodaki tüm karakterlerin Unicode numaralarına bakabilirsiniz . Özellikle yukarıdaki ilk üç karakteri burada , oku burada ve emojiyi burada bulabilirsiniz .

Tüm karakterlere Unicode tarafından atanan bu numaralara kod noktaları denir .

Tüm bunların amacı, her bir karaktere açık bir şekilde atıfta bulunmak için bir yol sağlamaktır. Örneğin, 😂'den bahsediyorsam, "bilirsiniz, gözyaşlarıyla bu gülen emoji" demek yerine, sadece Unicode kod noktası 0x1F602 diyebilirim . Daha kolay, değil mi?

Unicode kod noktalarının genellikle bir satır aralığı ile biçimlendirildiğini U+, ardından onaltılık sayısal değerin en az 4 haneye kadar doldurulduğunu unutmayın. Dolayısıyla, yukarıdaki örnekler U + 0041, U + 00E1, U + 0414, U + 2192, U + 1F602 olacaktır.

Unicode kod noktaları U + 0000 ile U + 10FFFF arasındadır. Bu 1,114,112 sayıdır. Bu sayıların 2048'i vekiller için kullanıldı , dolayısıyla 1.112.064 kaldı. Bu, Unicode'un 1.112.064 farklı karaktere benzersiz bir kimlik (kod noktası) atayabileceği anlamına gelir. Bu kod noktalarının tümü henüz bir karaktere atanmamıştır ve Unicode sürekli olarak genişletilir (örneğin, yeni emojiler sunulduğunda).

Unicode'un yaptığı tek şey, kolay ve kesin referans için her karaktere kod noktası adı verilen sayısal bir kimlik atamaktır.

Kodlamalar

Karakterleri bit desenleriyle eşleyin.

Bu bit desenleri, bilgisayar belleğindeki veya diskteki karakterleri temsil etmek için kullanılır.

Farklı karakter alt kümelerini kapsayan birçok farklı kodlama vardır. İngilizce konuşulan dünyada en yaygın kodlamalar şunlardır:

ASCII

Harita 128 karakter uzunluğunda 7 bit kalıplarına (U 007F için kod noktaları U +, 0000).

Misal:

  • a → 1100001 (0x61)

Bu tablodaki tüm eşlemeleri görebilirsiniz .

ISO 8859-1 (Latin-1 olarak da bilinir)

Harita 191 karakter uzunluğunda 8 bit kalıplarına (U 0020 U +, 00FF U + 007E ve u + 00A0 kod noktası).

Misal:

  • a → 01100001 (0x61)
  • á → 11100001 (0xE1)

Bu tablodaki tüm eşlemeleri görebilirsiniz .

UTF-8

Harita 1.112.064 karakter ya da uzunluğu 8, 16, 24, veya 32 bitlik bit kalıpları (bütün mevcut Unicode kod noktası) (yani, 1, 2, 3, ya da 4 bayt).

Misal:

  • a → 01100001 (0x61)
  • á → 11000011 10100001 (0xC3 0xA1)
  • ≠ → 11100010 10001001 10100000 (0xE2 0x89 0xA0)
  • 😂 → 11110000 10011111 10011000 10000010 (0xF0 0x9F 0x98 0x82)

UTF-8'in karakterleri bit dizelerine kodlama yöntemi burada çok iyi açıklanmıştır .

Unicode ve Kodlamalar

Yukarıdaki örneklere bakıldığında, Unicode'un ne kadar kullanışlı olduğu netleşiyor.

Örneğin, Latin-1 isem ve á kodlamamı açıklamak istiyorsam şunu söylememe gerek yok:

"Bunu aigu ile kodluyorum (veya siz buna yükselen çubuk diyorsunuz) 11100001"

Ama şunu söyleyebilirim:

"U + 00E1'i 11100001 olarak kodluyorum"

Ve UTF-8 isem şunu söyleyebilirim:

"Ben de sırayla, U + 00E1'i 11000011 10100001 olarak kodluyorum"

Ve hangi karakteri kastettiğimiz herkes için açık bir şekilde açıktır.

Şimdi sık sık ortaya çıkan kafa karışıklığına

Bazen bir kodlamanın bit deseninin, eğer onu bir ikili sayı olarak yorumlarsanız, bu karakterin Unicode kod noktasıyla aynı olduğu doğrudur.

Örneğin:

  • ASCII kodlar bir onaltılık sayı olarak yorumlayabilir 1100001 gibi 0x61 ve Unicode kod noktası bir olan U +, 0061 .
  • Latince-1 kodlar á Eğer on altılı sayı olarak yorumlayabilir 11100001 gibi 0XE1 ve Unicode kod noktası á olan U +, 00E1 .

Elbette kolaylık sağlamak amacıyla bu şekilde düzenlenmiştir. Ama buna saf bir tesadüf olarak bakmalısın . Bellekteki bir karakteri temsil etmek için kullanılan bit deseni, bu karakterin Unicode kod noktasına hiçbir şekilde bağlı değildir.

Hiç kimse 11100001 gibi bir bit dizgesini ikili sayı olarak yorumlamanız gerektiğini bile söylemiyor. Latin-1'in á karakterini kodlamak için kullandığı bit dizisi olarak bakın .

Sorunuza geri dönün

Python yorumlayıcınız tarafından kullanılan kodlama UTF-8'dir .

Örneklerinizde neler olduğu:

örnek 1

Aşağıdaki, UTF-8'de á karakterini kodlamaktadır. Bu, değişkene kaydedilen 11000011 10100001 bit dizesiyle sonuçlanır a.

>>> a = 'á'

Eğer değerine baktığımızda aiçeriği, 11000011 10100001 olarak altıgen numarası 0xC3 0xA1 ve çıktı olarak biçimlendirilir '\xc3\xa1':

>>> a
'\xc3\xa1'

Örnek 2

Aşağıdakiler, U + 00E1 olan á'nın Unicode kod noktasını değişkene uakaydeder (Python'un bellekte U + 00E1 kod noktasını temsil etmek için dahili olarak hangi veri biçimini kullandığını bilmiyoruz ve bu bizim için önemsizdir):

>>> ua = u'á'

Eğer değerine baktığımızda uaPython onun kod noktası U + 00E1 içerdiğini anlatır:

>>> ua
u'\xe1'

Örnek 3

Aşağıdaki kod noktası U + 00E1'i (karakter á'yı temsil eden) UTF-8 ile kodlar ve bu da 11000011 10100001 bit modeliyle sonuçlanır. Yine çıktı için bu bit modeli onaltılık sayı 0xC3 0xA1 olarak temsil edilir:

>>> ua.encode('utf-8')
'\xc3\xa1'

Örnek 4

Aşağıdaki kodlar Unicode kod noktası Latin-1, çıkış için bir bit dizisini 11100001. sonuçlanır bu bit şeklinin uygulanması heks numarası 0XE1 olarak temsil edilir U + 00E1 (temsil karakteri bir) tesadüfen ilk aynıdır kod noktası U + 00E1:

>>> ua.encode('latin1')
'\xe1'

Unicode nesnesi uaile Latin-1 kodlaması arasında bir ilişki yoktur . Á'nın kod noktasının U + 00E1 ve á'nın Latin-1 kodlamasının 0xE1 olması (kodlamanın bit modelini ikili sayı olarak yorumlarsanız) tamamen bir tesadüftür.


31

Terminaliniz UTF-8 olarak yapılandırılmış.

Matbaanın aişe yaraması bir tesadüf; terminale ham UTF-8 bayt yazıyorsunuz. auzunlukta bir değer iki ise iki bayt, hex değerleri C3 ve A1 içeren, uauzunlamasına bir Unicode değeri bir bir kod noktası U + 00E1 içeren.

Uzunluktaki bu fark, Unicode değerlerini kullanmanın başlıca nedenlerinden biridir; bir bayt dizesindeki metin karakterlerinin sayısını kolayca ölçemezsiniz ; len()Bir bayt dizi bir çok karakter kodlanmış edildi değil nasıl birçok bayt kullanıldı nasıl anlatır.

Unicode değerini farklı çıktı kodlamalarına kodladığınızda farkı görebilirsiniz :

>>> a = 'á'
>>> ua = u'á'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> a
'\xc3\xa1'

Unicode standardının ilk 256 kod noktasının Latin 1 standardıyla eşleştiğine dikkat edin, bu nedenle U + 00E1 kod noktası Latin 1'e onaltılık E1 değeriyle bayt olarak kodlanır.

Dahası, Python, hem unicode hem de bayt dizelerinin temsillerinde kaçış kodları kullanır ve yazdırılabilir olmayan düşük kod noktaları ASCII de \x..kaçış değerleri kullanılarak temsil edilir. Bu yüzden 128 ve 255 görünüyor arasında bir kod noktası ile Unicode dizesi sadece Latin 1 kodlama gibi. U + 00FF ötesinde kod noktalarına sahip bir unicode dizeniz varsa, \u....bunun yerine dört basamaklı onaltılık değerle farklı bir kaçış dizisi kullanılır.

Görünüşe göre Unicode ile kodlama arasındaki farkı henüz tam olarak anlamadınız. Lütfen devam etmeden önce aşağıdaki makaleleri okuyun:


Sorumu daha ileri testlerle düzenledim. Bir süredir unicode ve farklı kodlamalar için okuyorum ve sanırım teoriyi anlıyorum, ancak Python kodunu gerçekten test ederken neler olduğunu
anlamıyorum

1
Latin-1 kodlaması, Unicode standardının ilk 256 kod noktasıyla eşleşir. U + 00E1'in \xe1Latin 1 olarak kodlamasının nedeni budur .
Martijn Pieters

2
Unicode'un en önemli yönü budur. Bu bir kodlama değildir . Metin. Unicode, kod noktalarının sayı, boşluk veya diğer kategoriler gibi, soldan sağa veya sağdan sola vb. Gösterilmesi gereken bilgiler gibi çok daha fazlasını içeren bir standarttır.
Martijn Pieters

1
Tıpkı Unicode'un bir "Arayüz" ve Kodlamanın gerçek bir "Uygulama" gibi olduğunu söylemek gibi.
Caumons

2
@Varun: UCS-2'yi dahili olarak kullanan ve U + FFFF üzerindeki her şeyi iki uzunluğa sahip olarak yanlış gösteren bir Python 2 dar yapısı kullanıyor olmalısınız. Python 3 ve UCS-2 (geniş) yapısı size uzunluğun gerçekten 1 olduğunu gösterecek.
Martijn Pieters

2

A'yı unicode olarak tanımladığınızda, a ve á karakterleri eşittir. Aksi takdirde á iki karakter olarak sayılır. Len (a) ve len (au) 'yu deneyin. Buna ek olarak, diğer ortamlarla çalışırken kodlamaya sahip olmanız gerekebilir. Örneğin, md5 kullanırsanız, a ve ua için farklı değerler alırsınız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.