Bir dizenin unicode veya ascii olup olmadığını nasıl kontrol edebilirim?


271

Bir dizenin hangi kodlamasını kullandığını anlamak için Python'da ne yapmam gerekir?


56
Unicode bir kodlama değildir .
ulidtko

Daha da önemlisi, neden önemsemelisiniz?
Johnsyweb

@Johnsyweb Çünkü{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
alex

Yanıtlar:


295

Python 3'te, tüm dizeler Unicode karakter dizileridir. bytesHam bayt tutan bir tür vardır.

Python 2'de, bir dize türü strveya türü olabilir unicode. Hangi kodu kullanarak böyle bir şey söyleyebilirsiniz:

def whatisthis(s):
    if isinstance(s, str):
        print "ordinary string"
    elif isinstance(s, unicode):
        print "unicode string"
    else:
        print "not a string"

Bu "Unicode veya ASCII" yi ayırt etmez; sadece Python tiplerini ayırt eder. Bir Unicode dizesi yalnızca ASCII aralığındaki karakterlerden oluşabilir ve bir bytestring ASCII, kodlanmış Unicode ve hatta metinsel olmayan veriler içerebilir.


3
@ProsperousHeart: Muhtemelen Python 3 kullanıyorsunuz.
Greg Hewgill

124

Bir nesnenin bir unicode dizesi mi yoksa bayt dizesi mi olduğu nasıl anlaşılır

Sen kullanabilir typeya isinstance.

Python 2'de:

>>> type(u'abc')  # Python 2 unicode string literal
<type 'unicode'>
>>> type('abc')   # Python 2 byte string literal
<type 'str'>

Python 2'de strsadece bir bayt dizisidir. Python kodlamasının ne olduğunu bilmiyor. unicodeTip mağaza metne daha güvenli bir yoldur. Bunu daha fazla anlamak istiyorsanız, http://farmdev.com/talks/unicode/ adresini öneriyorum .

Python 3'te:

>>> type('abc')   # Python 3 unicode string literal
<class 'str'>
>>> type(b'abc')  # Python 3 byte string literal
<class 'bytes'>

Python 3'te strPython 2'ye benzer unicodeve metin depolamak için kullanılır. Ne denirdi strPython 2'de denir bytesPython 3'te.


Bayt dizesinin geçerli utf-8 veya ascii olup olmadığını nasıl anlarım

Arayabilirsiniz decode. UnicodeDecodeError istisnasını yükseltirse, geçerli değildi.

>>> u_umlaut = b'\xc3\x9c'   # UTF-8 representation of the letter 'Ü'
>>> u_umlaut.decode('utf-8')
u'\xdc'
>>> u_umlaut.decode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

Sadece başkalarının referansı için - pr.hon 3'te str.decode mevcut değil. Görünüşe göre öyle unicode(s, "ascii")ya da böyle
Shadow

3
Üzgünüm, demek istediğimstr(s, "ascii")
Shadow

1
Bu python 3 için doğru değil
ProsperousHeart

2
@ProsperousHeart Python 3'ü kapsayacak şekilde güncellendi. Ve bytestring'ler ile unicode dizeleri arasındaki farkı açıklamaya çalışmak.
Mikel

44

Python 3.x sürümünde tüm dizeler Unicode karakter dizileridir. ve str için isinstance kontrolünün (varsayılan olarak unicode string anlamına gelir) yapılması yeterli olacaktır.

isinstance(x, str)

Python 2.x ile ilgili olarak, çoğu insan iki kontrol içeren bir if ifadesi kullanıyor gibi görünüyor. biri str, diğeri unicode için.

Yine de tek bir deyimle 'dize benzeri' bir nesneniz olup olmadığını kontrol etmek istiyorsanız, aşağıdakileri yapabilirsiniz:

isinstance(x, basestring)

Bu yanlış. Python 2.7'de isinstance(u"x",basestring)geri döner True.
14'te

11
@PythonNut: Bunun önemli olduğuna inanıyorum. Isinstance (x, basestring) kullanımı yukarıdaki farklı ikili testlerin yerini almak için yeterlidir.
KQ.

5
Birçok durumda yararlıdır, ancak sorgulayıcının ne anlama geldiği açık değildir.
mhsmith

3
Bu sorunun cevabıdır. Diğerleri OP'nin söylediklerini yanlış anladı ve Python'da tip kontrolü hakkında genel cevaplar verdi.
fiatjaf

1
OP'nin sorusuna cevap vermiyor. Sorunun başlığı (yalnız) Bu cevap doğru olacak şekilde yorumlanabilir. Ancak OP özellikle sorunun açıklamasında "hangisini bul" yazıyor ve bu cevap buna değinmiyor.
MD004

31

Unicode bir kodlama değildir - Kumar McMillan'a alıntı yapmak için:

ASCII, UTF-8 ve diğer bayt dizeleri "metin" ise ...

... o zaman Unicode "metin" dir;

metnin soyut biçimidir

McMillan'ın Unicode In Python'u okuyun, PyCon 2008'den Tamamen Demystified konuşması, Stack Overflow'daki ilgili cevapların çoğundan çok daha iyi şeyler açıklıyor.


Bu slaytlar muhtemelen bugüne kadar karşılaştığım Unicode için en iyi giriş
Jonny

23

Kod ihtiyaçları ile uyumlu olacak şekilde olursa hem Python 2 ve Python 3, doğrudan gibi şeyler kullanamaz isinstance(s,bytes)veya isinstance(s,unicode)çünkü haricinde veya bir piton sürüm test / ya denemede onları sarma olmadan bytesPython 2 tanımlanmamış ve unicodePython 3 tanımlanmamış .

Bazı çirkin çözümler var. Son derece çirkin olanı, türün kendisini karşılaştırmak yerine türün adını karşılaştırmaktır. İşte bir örnek:

# convert bytes (python 3) or unicode (python 2) to str
if str(type(s)) == "<class 'bytes'>":
    # only possible in Python 3
    s = s.decode('ascii')  # or  s = str(s)[2:-1]
elif str(type(s)) == "<type 'unicode'>":
    # only possible in Python 2
    s = str(s)

Tartışmasız biraz daha az çirkin bir çözüm, Python sürüm numarasını kontrol etmektir, örneğin:

if sys.version_info >= (3,0,0):
    # for Python 3
    if isinstance(s, bytes):
        s = s.decode('ascii')  # or  s = str(s)[2:-1]
else:
    # for Python 2
    if isinstance(s, unicode):
        s = str(s)

Her ikisi de unpythonic ve çoğu zaman muhtemelen daha iyi bir yol var.


6
En iyi yol muhtemelen kullanmak sixve test etmek six.binary_typevesix.text_type
Ian Clelland

1
Sen kullanabilirsiniz name__ türü (ler) .__ tipi adlarını araştırmak için.
Paulo Freitas

Bir mantık hatası olmadıkça, bu kod biraz kullanım durumundan emin değilim. Bence python 2 kodunda bir "değil" olmalı. Aksi takdirde, her şeyi Python 3 için unicode dizelerine ve Python 2 için tersine dönüştürüyorsunuz!
oligofren

Evet, oligofren, işte böyle. Standart iç dizeler Python 3'te Unicode ve Python 2'de ASCII'dir. Böylece kod parçacıkları metni standart iç dize türüne dönüştürür (Unicode veya ASCII olsun).
Dave Burton

12

kullanın:

import six
if isinstance(obj, six.text_type)

altı kütüphanenin içinde şu şekilde temsil edilir:

if PY3:
    string_types = str,
else:
    string_types = basestring,

2
olmalı if isinstance(obj, six.text_type) . Ama evet bu doğru cevap imo.
karantan

OP'nin sorusuna cevap vermiyor. Sorunun başlığı (yalnız) Bu cevap doğru olacak şekilde yorumlanabilir. Ancak OP özellikle sorunun açıklamasında "hangisini bul" yazıyor ve bu cevap buna değinmiyor.
MD004

4

Python 3'te aşağıdakilerden herhangi birini söylemek gerçekten adil değil:

  • strs herhangi bir x için UTFx'tir (örneğin UTF8)

  • strs Unicode

  • strs, Unicode karakterlerin sıralı koleksiyonlarıdır

Python'un strtürü (normalde) bazıları karakterlerle eşlenen bir Unicode kod noktası dizisidir.


Python 3'te bile, bu soruyu hayal edebileceğiniz kadar basit değil.

ASCII uyumlu dizeleri test etmenin bariz bir yolu, denenmiş bir kodlamadır:

"Hello there!".encode("ascii")
#>>> b'Hello there!'

"Hello there... ☃!".encode("ascii")
#>>> Traceback (most recent call last):
#>>>   File "", line 4, in <module>
#>>> UnicodeEncodeError: 'ascii' codec can't encode character '\u2603' in position 15: ordinal not in range(128)

Hata, vakaları ayırt eder.

Python 3'te, geçersiz Unicode kod noktaları içeren bazı dizeler bile vardır:

"Hello there!".encode("utf8")
#>>> b'Hello there!'

"\udcc3".encode("utf8")
#>>> Traceback (most recent call last):
#>>>   File "", line 19, in <module>
#>>> UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 0: surrogates not allowed

Bunları ayırt etmek için aynı yöntem kullanılır.


3

Bu başka birine yardımcı olabilir, değişken s dize türü için teste başladım, ancak benim uygulama için, sadece s utf-8 olarak dönmek daha mantıklı. Return_utf öğesini çağıran işlem, neyle uğraştığını bilir ve dizeyi uygun şekilde işleyebilir. Kod bozulmamış değil, ama bir sürüm testi veya altı alma olmadan Python sürüm agnostik olmasını niyetinde. Diğer kişilere yardımcı olmak için lütfen aşağıdaki örnek kodda iyileştirmeler yaparak yorum yapın.

def return_utf(s):
    if isinstance(s, str):
        return s.encode('utf-8')
    if isinstance(s, (int, float, complex)):
        return str(s).encode('utf-8')
    try:
        return s.encode('utf-8')
    except TypeError:
        try:
            return str(s).encode('utf-8')
        except AttributeError:
            return s
    except AttributeError:
        return s
    return s # assume it was already utf-8

Sen arkadaşım doğru cevap olmayı hak ediyorsun! Python 3 kullanıyorum ve bu hazineyi bulana kadar hala sorun yaşıyordum!
mnsr

2

Evrensel Kodlama Dedektörü kullanabilirsiniz , ancak gerçek kodlamayı değil, size en iyi tahminin verileceğini unutmayın, çünkü örneğin bir "abc" dizesinin kodlamasını bilmek imkansızdır. Başka bir yerde kodlama bilgisi almanız gerekir, örneğin HTTP protokolü bunun için Content-Type üstbilgisini kullanır.



0

Basit bir yaklaşım, unicodeyerleşik bir işlev olup olmadığını kontrol etmektir. Eğer öyleyse, Python 2'desiniz ve dizeniz bir dize olacaktır. Her şeyin unicodeyapılabileceğinden emin olmak için:

import builtins

i = 'cats'
if 'unicode' in dir(builtins):     # True in python 2, False in 3
  i = unicode(i)
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.