Como verifico se uma string é unicode ou ascii?


271

O que devo fazer no Python para descobrir qual codificação uma string possui?


56
Unicode não é uma codificação.
111311 ulidtko

Mais importante, por que você deveria se importar?
Johnsyweb 14/02

@Johnsyweb Por causa de{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
alex

Respostas:


295

No Python 3, todas as strings são seqüências de caracteres Unicode. Há um bytestipo que contém bytes brutos.

No Python 2, uma string pode ser do tipo strou do tipo unicode. Você pode dizer qual código usando algo parecido com isto:

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

Isso não distingue "Unicode ou ASCII"; apenas distingue os tipos Python. Uma cadeia de caracteres Unicode pode consistir em caracteres puramente no intervalo ASCII, e uma cadeia de bytes pode conter dados ASCII, Unicode codificados ou mesmo não textuais.


3
@ProsperousHeart: Você provavelmente está usando Python 3.
Greg Hewgill

124

Como saber se um objeto é uma string unicode ou byte

Você pode usar typeou isinstance.

No Python 2:

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

No Python 2, stré apenas uma sequência de bytes. Python não sabe qual é a sua codificação. O unicodetipo é a maneira mais segura de armazenar texto. Se você quiser entender mais isso, recomendo http://farmdev.com/talks/unicode/ .

No Python 3:

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

No Python 3, stré como o Python 2 unicodee é usado para armazenar texto. O que foi chamado strno Python 2 é chamado bytesno Python 3.


Como saber se uma sequência de bytes é válida utf-8 ou ascii

Você pode ligar decode. Se gerar uma exceção UnicodeDecodeError, não será válido.

>>> 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)

Apenas para referência de outras pessoas - str.decode não não existe em python 3. Parece que você tem que unicode(s, "ascii")ou algo
Sombra

3
Desculpe, eu quis dizerstr(s, "ascii")
Sombra

1
Isso não é preciso para python 3
ProsperousHeart

2
@ProsperousHeart Atualizado para cobrir o Python 3. E para tentar explicar a diferença entre bytestrings e unicode.
Mikel

44

No python 3.x, todas as strings são seqüências de caracteres Unicode. e fazer a verificação isinstance para str (que significa string unicode por padrão) deve ser suficiente.

isinstance(x, str)

Com relação ao python 2.x, a maioria das pessoas parece estar usando uma instrução if com duas verificações. um para str e outro para unicode.

Se você quiser verificar se possui um objeto 'semelhante a uma string', com apenas uma instrução, faça o seguinte:

isinstance(x, basestring)

Isto é falso. No Python 2.7 isinstance(u"x",basestring)retorna True.
precisa saber é o seguinte

11
@ PythonNut: Eu acredito que esse era o ponto. O uso de isinstance (x, basestring) é suficiente para substituir os distintos testes duplos acima.
KQ.

5
É útil em muitos casos, mas evidentemente não é o que o questionador quis dizer.
mhsmith

3
Essa é a resposta para a pergunta. Todos os outros entenderam mal o que o OP disse e deram respostas genéricas sobre a verificação de tipos no Python.
Fiatjaf 11/04/2015

1
Não responde à pergunta do OP. O título da pergunta (sozinho) PODE ser interpretado de forma que esta resposta esteja correta. No entanto, o OP diz especificamente "descobrir qual" na descrição da pergunta, e esta resposta não aborda isso.
MD004

31

Unicode não é uma codificação - para citar Kumar McMillan:

Se ASCII, UTF-8 e outras cadeias de bytes são "texto" ...

... então Unicode é "text-ness";

é a forma abstrata do texto

Leia a palestra Unicode In Python, completamente desmistificada do PyCon 2008, da McMillan, que explica as coisas muito melhor do que a maioria das respostas relacionadas ao Stack Overflow.


Esses slides são provavelmente a melhor introdução ao Unicode que eu já vi até agora
Jonny

23

Se as suas necessidades de código para ser compatível com ambos Python 2 e Python 3, você não pode usar diretamente coisas como isinstance(s,bytes)ou isinstance(s,unicode)sem colocá-los em qualquer try / exceto ou um teste de versão python, porque bytesé indefinido em Python 2 e unicodeé indefinido em Python 3 .

Existem algumas soluções feias. Uma coisa extremamente feia é comparar o nome do tipo, em vez de comparar o próprio tipo. Aqui está um exemplo:

# 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)

Uma solução indiscutivelmente um pouco menos feia é verificar o número da versão do Python, por exemplo:

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)

Ambos são não-tônicos, e na maioria das vezes provavelmente existe uma maneira melhor.


6
A melhor maneira é provavelmente usar sixe testar contra six.binary_typeesix.text_type
Ian Clelland

1
Você pode usar o (s) tipo (s) .__ name__ para pesquisar nomes de tipo.
Paulo Freitas

Não tenho muita certeza do caso de uso desse bit de código, a menos que haja um erro lógico. Eu acho que deveria haver um "não" no código python 2. Caso contrário, você está convertendo tudo em cadeias unicode para Python 3 e o oposto para Python 2!
precisa

Sim, oligofren, é o que faz. As cadeias internas padrão são Unicode no Python 3 e ASCII no Python 2. Portanto, os trechos de código convertem texto em tipo de cadeia interna padrão (seja Unicode ou ASCII).
Dave Burton

12

usar:

import six
if isinstance(obj, six.text_type)

dentro da biblioteca seis é representado como:

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

2
deveria ser if isinstance(obj, six.text_type) . Mas sim, esta é a resposta correta.
karantan

Não responde à pergunta do OP. O título da pergunta (sozinho) PODE ser interpretado de forma que esta resposta esteja correta. No entanto, o OP diz especificamente "descobrir qual" na descrição da pergunta, e esta resposta não aborda isso.
MD004

4

Observe que no Python 3, não é realmente justo dizer um dos seguintes:

  • strs são UTFx para qualquer x (por exemplo, UTF8)

  • strs são Unicode

  • strs são coleções ordenadas de caracteres Unicode

O strtipo de Python é (normalmente) uma sequência de pontos de código Unicode, alguns dos quais são mapeados para caracteres.


Mesmo no Python 3, não é tão simples responder a essa pergunta como você pode imaginar.

Uma maneira óbvia de testar cadeias compatíveis com ASCII é através de uma tentativa de codificação:

"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)

O erro distingue os casos.

No Python 3, existem até algumas strings que contêm pontos de código Unicode inválidos:

"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

O mesmo método para distingui-los é usado.


3

Isso pode ajudar outra pessoa. Comecei a testar o tipo de string da variável s, mas, para meu aplicativo, fazia mais sentido simplesmente retornar s como utf-8. O processo que chama return_utf, então sabe com o que está lidando e pode manipular a sequência adequadamente. O código não é puro, mas pretendo que ele seja independente da versão Python sem um teste de versão ou sem importar seis. Comente com melhorias no código de exemplo abaixo para ajudar outras pessoas.

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

Você meu amigo merece ser a resposta correta! Estou usando o python 3 e ainda estava tendo problemas até encontrar esse tesouro!
MNSR

2

Você pode usar o Universal Encoding Detector , mas lembre-se de que ele fornecerá o melhor palpite, não a codificação real, porque é impossível saber a codificação de uma string "abc", por exemplo. Você precisará obter informações de codificação em outro lugar, por exemplo, o protocolo HTTP usa o cabeçalho Content-Type para isso.


0

Para compatibilidade com py2 / py3, basta usar

import six if isinstance(obj, six.text_type)


0

Uma abordagem simples é verificar se unicodeé uma função interna. Nesse caso, você está no Python 2 e sua string será uma string. Para garantir que tudo está em unicodeum pode fazer:

import builtins

i = 'cats'
if 'unicode' in dir(builtins):     # True in python 2, False in 3
  i = unicode(i)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.