Qual é a diferença entre uma sequência de caracteres e uma sequência de bytes?

209

Estou trabalhando com uma biblioteca que retorna uma string de bytes e preciso convertê-la em uma string.

Embora eu não tenha certeza de qual seja a diferença - se houver.

Sheldon
fonte

Respostas:

260

Supondo que o Python 3 (no Python 2, essa diferença seja um pouco menos bem definida) - uma string é uma sequência de caracteres, ou seja, pontos de código unicode ; esse é um conceito abstrato e não pode ser armazenado diretamente no disco. Uma string de bytes é uma sequência de bytes, sem surpresa, coisas que podem ser armazenadas em disco. O mapeamento entre eles é uma codificação - existem muitas delas (e infinitas são possíveis) - e você precisa saber o que se aplica no caso específico para fazer a conversão, pois uma codificação diferente pode mapear os mesmos bytes para uma sequência diferente:

>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-16')
'蓏콯캁澽苏'
>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-8')
'τoρνoς'

Depois de saber qual usar, você pode usar o .decode()método da cadeia de bytes para obter a cadeia de caracteres correta como acima. Para completar, o .encode()método de uma sequência de caracteres segue o caminho oposto:

>>> 'τoρνoς'.encode('utf-8')
b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'
lvc
fonte
7
Para esclarecer aos usuários do Python 2: o strtipo é o mesmo que o bytestipo; esta resposta está comparando equivalentemente o unicodetipo (não existe no Python 3) ao strtipo.
Craymichael
3
@KshitijSaraogi que também não é verdade; essa frase inteira foi editada e é um pouco infeliz. A representação na memória de strobjetos Python 3 não é acessível ou relevante do lado Python; a estrutura de dados é apenas uma sequência de pontos de código. De acordo com o PEP 393 , a codificação interna exata é Latina-1, UCS2 ou UCS4, e uma representação utf-8 pode ser armazenada em cache após ser solicitada pela primeira vez, mas mesmo o código C é desencorajado de depender desses detalhes internos.
Lvc
1
Se eles não podem ser armazenados diretamente no disco, como são armazenados na memória?
Z33k
2
@orety eles precisam ser codificados de alguma forma internamente exatamente por esse motivo, mas isso não é exposto a você a partir do código Python, assim como você não precisa se preocupar com o armazenamento de números de ponto flutuante.
Lvc
1
@ChrisStryczynski vê os comentários acima - com certeza eles estão armazenados na memória de alguma forma , mas esse formulário é explicitamente abstraído. De fato, atualmente, ele pode mudar durante a vida útil de um programa e ser diferente entre cadeias diferentes ou pode até ser mais de uma (algumas codificações são armazenadas em cache), dependendo dos caracteres nelas - mas a única vez em que você precisa se preocupar isto é, se você estiver invadindo a implementação do próprio tipo de string.
lvc 16/02
390

A única coisa que um computador pode armazenar são bytes.

Para armazenar qualquer coisa em um computador, você deve primeiro codificá- lo, ou seja, convertê-lo em bytes. Por exemplo:

  • Se você deseja armazenar música, primeiro você deve codificar -lo usando MP3, WAVetc.
  • Se você deseja armazenar uma imagem, você deve primeiro codificar -lo usando PNG, JPEGetc.
  • Se você deseja armazenar texto, primeiro você deve codificar -lo usando ASCII, UTF-8etc.

MP3, WAV, PNG, JPEG, ASCIIE UTF-8são exemplos de codificações . Uma codificação é um formato para representar áudio, imagens, texto etc. em bytes.

No Python, uma sequência de bytes é exatamente isso: uma sequência de bytes. Não é legível por humanos. Sob o capô, tudo deve ser convertido em uma sequência de bytes para que possa ser armazenado em um computador.

Por outro lado, uma cadeia de caracteres, geralmente chamada de "cadeia", é uma sequência de caracteres. É legível por humanos. Uma cadeia de caracteres não pode ser armazenada diretamente em um computador; ela deve ser codificada primeiro (convertida em uma cadeia de bytes). Existem várias codificações através das quais uma sequência de caracteres pode ser convertida em uma sequência de bytes, como ASCIIe UTF-8.

'I am a string'.encode('ASCII')

O código Python acima codificará a string 'I am a string'usando a codificação ASCII. O resultado do código acima será uma sequência de bytes. Se você o imprimir, o Python o representará como b'I am a string'. Lembre-se, no entanto, que as cadeias de bytes não são legíveis por humanos , é só que o Python as decodifica ASCIIquando as imprime. No Python, uma sequência de bytes é representada por a b, seguida pela ASCIIrepresentação da sequência de bytes .

Uma sequência de bytes pode ser decodificada novamente em uma sequência de caracteres, se você souber a codificação usada para codificá-la.

b'I am a string'.decode('ASCII')

O código acima retornará a string original 'I am a string'.

Codificação e decodificação são operações inversas. Tudo deve ser codificado antes de poder ser gravado no disco e deve ser decodificado antes de poder ser lido por um ser humano.

Zenadix
fonte
59
O Zenadix merece alguns elogios aqui. Depois de alguns anos trabalhando nesse ambiente, a dele é a primeira explicação que me ocorreu. Eu posso tatuar no meu outro braço (um já braço tem "O desenvolvedor Absolute Minimum cada Software Absolutamente, Positivamente Precisa Saber Sobre Unicode e Conjuntos de caracteres (Sem Desculpas) por Joel Spolsky!"
neil.millikin
4
Absolutamente brilhante. Lúcido e fácil de entender. No entanto, gostaria de mencionar que esta linha - "Se você a imprimir, o Python a representará como b'Eu sou uma string '" é verdadeira para o Python3, assim como para os bytes do Python2 e str são a mesma coisa.
SRC
5
Estou concedendo a você essa recompensa por oferecer uma explicação muito legível ao ser humano para esclarecer esse assunto!
fedorqui 'Então, pare de prejudicar'
3
Ótima resposta. A única coisa que talvez possa ser adicionada é apontar com mais clareza que, historicamente, programadores e linguagens de programação tendem a assumir explícita ou implicitamente que uma sequência de bytes e uma string ASCII eram a mesma coisa . Python 3 decidiu quebrar explicitamente essa suposição, corretamente IMHO.
Nekomatic
4
Link para a publicação de Joel mencionada por @ neil.millikin acima: joelonsoftware.com/2003/10/08/…
Kshitij Saraogi
14

Nota: Vou elaborar mais minha resposta para o Python 3, pois o final da vida útil do Python 2 está muito próximo.

No Python 3

bytesconsiste em sequências de valores não assinados de 8 bits, enquanto que strconsiste em sequências de pontos de código Unicode que representam caracteres textuais de idiomas humanos.

>>> # bytes
>>> b = b'h\x65llo'
>>> type(b)
<class 'bytes'>
>>> list(b)
[104, 101, 108, 108, 111]
>>> print(b)
b'hello'
>>>
>>> # str
>>> s = 'nai\u0308ve'
>>> type(s)
<class 'str'>
>>> list(s)
['n', 'a', 'i', '̈', 'v', 'e']
>>> print(s)
naïve

Embora bytese strparecem funcionar da mesma maneira, suas instâncias não são compatíveis uns com os outros, ou seja, bytese strinstâncias não podem ser utilizados em conjunto com operadoras como >e +. Além disso, lembre-se de que a comparação bytese as strinstâncias de igualdade, ou seja ==, o uso , sempre serão avaliadas Falsemesmo quando elas contêm exatamente os mesmos caracteres.

>>> # concatenation
>>> b'hi' + b'bye' # this is possible
b'hibye'
>>> 'hi' + 'bye' # this is also possible
'hibye'
>>> b'hi' + 'bye' # this will fail
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat str to bytes
>>> 'hi' + b'bye' # this will also fail
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "bytes") to str
>>>
>>> # comparison
>>> b'red' > b'blue' # this is possible
True
>>> 'red'> 'blue' # this is also possible
True
>>> b'red' > 'blue' # you can't compare bytes with str
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'bytes' and 'str'
>>> 'red' > b'blue' # you can't compare str with bytes
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'str' and 'bytes'
>>> b'blue' == 'red' # equality between str and bytes always evaluates to False
False
>>> b'blue' == 'blue' # equality between str and bytes always evaluates to False
False

Outro problema ao lidar com bytese strestá presente ao trabalhar com arquivos retornados usando a openfunção interna. Por um lado, se você deseja ler ou gravar dados binários de / para um arquivo, sempre abra o arquivo usando um modo binário como 'rb' ou 'wb'. Por outro lado, se você quiser ler ou gravar dados Unicode em / de um arquivo, esteja ciente da codificação padrão do seu computador; portanto, se necessário, passe o encodingparâmetro para evitar surpresas.

No Python 2

strconsiste em sequências de valores de 8 bits, enquanto que unicodeconsiste em sequências de caracteres Unicode. Um aspecto a ter em mente é que stre unicodepode ser usado junto com os operadores, se strconsistir apenas em caracteres ASCI de 7 bits.

Pode ser útil usar funções auxiliares para converter entre stre unicodeno Python 2 e entre bytese strno Python 3.

lmiguelvargasf
fonte
4

Do que é Unicode :

Fundamentalmente, os computadores apenas lidam com números. Eles armazenam letras e outros caracteres atribuindo um número para cada um.

......

O Unicode fornece um número único para cada caractere, independentemente da plataforma, do programa, do idioma.

Portanto, quando um computador representa uma sequência, ele encontra caracteres armazenados no computador da sequência através de seu número Unicode exclusivo e esses números são armazenados na memória. Mas você não pode gravar diretamente a sequência em disco ou transmiti-la na rede através do número Unicode exclusivo, porque esses números são apenas um número decimal simples. Você deve codificar a sequência de caracteres em bytes, como UTF-8. UTF-8é uma codificação de caracteres capaz de codificar todos os caracteres possíveis e armazena caracteres como bytes (parece com isso ). Portanto, a cadeia codificada pode ser usada em qualquer lugar porque UTF-8é quase suportada em qualquer lugar. Quando você abre um arquivo de texto codificado emUTF-8de outros sistemas, o computador o decodificará e exibirá os caracteres através do número Unicode exclusivo. Quando um navegador recebe dados de string codificados UTF-8da rede, ele os decodifica em string (assuma o navegador na UTF-8codificação) e exibe a string.

Em python3, você pode transformar string e string de bytes entre si:

>>> print('中文'.encode('utf-8'))
b'\xe4\xb8\xad\xe6\x96\x87'
>>> print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8'))
中文 

Em uma palavra, string é para exibir para humanos ler em um computador e byte string é para armazenar em disco e transmissão de dados.

Sam Yang
fonte
1

Unicode é um formato acordado para a representação binária de caracteres e vários tipos de formatação (por exemplo, letras minúsculas / maiúsculas, nova linha, retorno de carro) e outras "coisas" (por exemplo, emojis). Um computador não é menos capaz de armazenar uma representação unicode (uma série de bits), na memória ou em um arquivo, do que armazenar uma representação ascii (uma série diferente de bits) ou qualquer outra representação (série de bits) )

Para que a comunicação ocorra, as partes na comunicação devem concordar sobre qual representação será usada.

Como o unicode procura representar todos os caracteres possíveis (e outras "coisas") usados ​​na comunicação entre humanos e entre computadores, requer um número maior de bits para a representação de muitos caracteres (ou coisas) do que outros sistemas de representação que procure representar um conjunto mais limitado de caracteres / coisas. Para "simplificar" e talvez acomodar o uso histórico, a representação unicode é quase exclusivamente convertida em outro sistema de representação (por exemplo, ascii) com o objetivo de armazenar caracteres em arquivos.

Não é o caso que o unicode não possa ser usado para armazenar caracteres em arquivos ou transmiti-los por qualquer canal de comunicação, simplesmente que não é .

O termo "string" não é definido com precisão. "String", em seu uso comum, refere-se a um conjunto de caracteres / coisas. Em um computador, esses caracteres podem ser armazenados em qualquer uma das diversas representações bit a bit. Uma "sequência de bytes" é um conjunto de caracteres armazenados usando uma representação que usa oito bits (oito bits sendo referidos como byte). Como atualmente, os computadores usam o sistema unicode (caracteres representados por um número variável de bytes) para armazenar caracteres na memória e cadeias de bytes (caracteres representados por bytes únicos) para armazenar caracteres em arquivos, uma conversão deve ser usada antes dos caracteres representados na memória serão movidos para o armazenamento em arquivos.

Gordon Shephard
fonte
0

Vamos ter uma cadeia simples de um caractere 'š'e codificá-la em uma sequência de bytes:

>>> 'š'.encode('utf-8')
b'\xc5\xa1'

Para os fins deste exemplo, vamos exibir a sequência de bytes em sua forma binária:

>>> bin(int(b'\xc5\xa1'.hex(), 16))
'0b1100010110100001'

Agora, geralmente não é possível decodificar as informações sem saber como elas foram codificadas. Somente se você souber que a utf-8codificação de texto foi usada, poderá seguir o algoritmo para decodificar utf-8 e adquirir a sequência original:

11000101 10100001
   ^^^^^   ^^^^^^
   00101   100001

Você pode exibir o número binário de 101100001volta como uma sequência:

>>> chr(int('101100001', 2))
'š'
Jeyekomon
fonte
0

As linguagens Python incluem stre bytescomo "Tipos incorporados" padrão. Em outras palavras, são duas classes. Eu não acho que vale a pena tentar racionalizar por que o Python foi implementado dessa maneira.

Dito isto, stre bytessão muito parecidos entre si. Ambos compartilham a maioria dos mesmos métodos. Os seguintes métodos são exclusivos para a strclasse:

casefold
encode
format
format_map
isdecimal
isidentifier
isnumeric
isprintable

Os seguintes métodos são exclusivos para a bytesclasse:

decode
fromhex
hex
fiftytwocards
fonte