Qual è la differenza tra una stringa e una stringa di byte?


210

Sto lavorando con una libreria che restituisce una stringa di byte e devo convertirla in una stringa.

Anche se non sono sicuro di quale sia la differenza, se presente.

Risposte:


261

Supponendo Python 3 (in Python 2, questa differenza è un po 'meno ben definita) - una stringa è una sequenza di caratteri, cioè punti di codice unicode ; questi sono concetti astratti e non possono essere archiviati direttamente su disco. Una stringa di byte è una sequenza, ovviamente, di byte: elementi che possono essere memorizzati su disco. La mappatura tra loro è una codifica - ce ne sono molte (e infinitamente molte sono possibili) - e devi sapere quale si applica nel caso particolare per fare la conversione, poiché una codifica diversa può mappare gli stessi byte a una stringa diversa:

>>> 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ς'

Una volta che sai quale usare, puoi usare il .decode()metodo della stringa di byte per ottenere la stringa di caratteri corretta come sopra. Per completezza, il .encode()metodo di una stringa di caratteri va nella direzione opposta:

>>> 'τoρνoς'.encode('utf-8')
b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'

7
Per chiarire gli utenti di Python 2: il strtipo è uguale al bytestipo; questa risposta confronta in modo equivalente il unicodetipo (non esiste in Python 3) con il strtipo.
Craymichael,

3
@KshitijSaraogi neanche questo è del tutto vero; l'intera frase è stata modificata ed è un po 'sfortunata. La rappresentazione in memoria degli stroggetti Python 3 non è accessibile o rilevante dal lato Python; la struttura dei dati è solo una sequenza di punti di codice. In base a PEP 393 , la codifica interna esatta è una di Latin-1, UCS2 o UCS4 e una rappresentazione utf-8 può essere memorizzata nella cache dopo che è stata richiesta per la prima volta, ma anche il codice C è scoraggiato dal fare affidamento su questi dettagli interni.
PVC,

1
Se non possono essere archiviati direttamente su disco, come possono essere archiviati in memoria?
z33k,

2
A volte devono essere codificati in qualche modo internamente esattamente per quel motivo, ma questo non è il modo in cui ti esponi dal codice Python come se non dovessi preoccuparti di come sono memorizzati i numeri in virgola mobile.
PVC

1
@ChrisStryczynski vede i commenti sopra - sicuramente sono memorizzati in qualche modo nella memoria , ma quel modulo è esplicitamente estratto. In effetti, in questi giorni, può cambiare durante la vita di un programma ed essere diverso tra stringhe diverse o potrebbe anche essere più di uno (alcune codifiche sono memorizzate nella cache), a seconda dei caratteri in esse - ma l'unica volta che devi preoccuparti cioè se stai hackerando l'implementazione del tipo di stringa stesso.
PVC

390

L'unica cosa che un computer può memorizzare sono i byte.

Per archiviare qualsiasi cosa in un computer, devi prima codificarlo , ovvero convertirlo in byte. Per esempio:

  • Se si desidera memorizzare la musica, è necessario prima di codificare utilizzando MP3, WAVecc
  • Se si desidera memorizzare una foto, è necessario prima di codificare utilizzando PNG, JPEGecc
  • Se si desidera memorizzare il testo, è necessario prima di codificare utilizzando ASCII, UTF-8ecc

MP3, WAV, PNG, JPEG, ASCIIE UTF-8sono esempi di codifiche . Una codifica è un formato per rappresentare audio, immagini, testo, ecc. In byte.

In Python, una stringa di byte è proprio questa: una sequenza di byte. Non è leggibile dall'uomo. Sotto il cofano, tutto deve essere convertito in una stringa di byte prima di poter essere memorizzato in un computer.

D'altra parte, una stringa di caratteri, spesso chiamata semplicemente "stringa", è una sequenza di caratteri. È leggibile dall'uomo. Una stringa di caratteri non può essere archiviata direttamente in un computer, deve essere prima codificata (convertita in una stringa di byte). Esistono più codifiche attraverso le quali una stringa di caratteri può essere convertita in una stringa di byte, come ASCIIe UTF-8.

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

Il codice Python sopra codificherà la stringa 'I am a string'usando la codifica ASCII. Il risultato del codice sopra sarà una stringa di byte. Se lo stampi, Python lo rappresenterà come b'I am a string'. Ricorda, tuttavia, che le stringhe di byte non sono leggibili dall'uomo , è solo che Python le decodifica da ASCIIquando le stampi. In Python, una stringa di byte è rappresentata da a b, seguita dalla ASCIIrappresentazione della stringa di byte .

Una stringa di byte può essere decodificata nuovamente in una stringa di caratteri, se si conosce la codifica utilizzata per codificarla.

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

Il codice sopra restituirà la stringa originale 'I am a string'.

La codifica e la decodifica sono operazioni inverse. Tutto deve essere codificato prima di poter essere scritto su disco e deve essere decodificato prima di poter essere letto da un essere umano.


59
Zenadix merita alcuni complimenti qui. Dopo alcuni anni di funzionamento in questo ambiente, la sua è la prima spiegazione che mi ha fatto clic. Posso tatuarlo sull'altro braccio (un braccio ha già "Il minimo assoluto che ogni sviluppatore di software deve assolutamente conoscere positivamente sugli Unicode e sui set di caratteri (senza scuse!) Di Joel Spolsky"
neil.millikin,

4
Assolutamente brillante. Lucido e facile da capire. Tuttavia, vorrei ricordare che questa riga: "Se la stampi, Python la rappresenterà come b'I am a string" "è vera per Python3 come per Python2 byte e str sono la stessa cosa.
SRC,

5
Ti sto assegnando questo dono per aver offerto una spiegazione molto leggibile dall'uomo per chiarire un po 'l'argomento!
fedorqui "SO smettere di danneggiare" l'

3
Bella risposta. L'unica cosa che potrebbe forse essere aggiunta è sottolineare più chiaramente che storicamente, i programmatori e i linguaggi di programmazione hanno teso ad assumere esplicitamente o implicitamente che una sequenza di byte e una stringa ASCII fossero la stessa cosa . Python 3 ha deciso di rompere esplicitamente questo presupposto, correttamente IMHO.
Nekomatic

4
Link al post di Joel menzionato da @ neil.millikin sopra: joelonsoftware.com/2003/10/08/…
Kshitij Saraogi

14

Nota: elaborerò di più la mia risposta per Python 3 poiché la fine della vita di Python 2 è molto vicina.

In Python 3

bytesè costituito da sequenze di valori senza segno a 8 bit, mentre è strcostituito da sequenze di punti di codice Unicode che rappresentano caratteri testuali da linguaggi umani.

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

Anche se bytese strsembra funzionare allo stesso modo, i loro casi non sono compatibili tra di loro, vale a dire, bytese strle istanze non possono essere utilizzati insieme con gli operatori come >e +. Inoltre, tieni presente che il confronto bytese le stristanze per l'uguaglianza, ovvero l'utilizzo ==, valuteranno sempre Falseanche quando contengono esattamente gli stessi caratteri.

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

Un altro problema quando si ha a che fare con bytesed strè presente quando si lavora con file restituiti utilizzando la openfunzione integrata. Da un lato, se desideri leggere o scrivere dati binari su / da un file, apri sempre il file usando una modalità binaria come 'rb' o 'wb'. D'altra parte, se si desidera leggere o scrivere dati Unicode su / da un file, tenere presente la codifica predefinita del computer, quindi, se necessario, passare il encodingparametro per evitare sorprese.

In Python 2

strè costituito da sequenze di valori a 8 bit, mentre è unicodecostituito da sequenze di caratteri Unicode. Una cosa da tenere a mente è che stre unicodepossono essere utilizzati insieme con gli operatori, se strsolo si compone di caratteri ASCI 7-bit.

Potrebbe essere utile utilizzare le funzioni di supporto per convertire tra stre unicodein Python 2 e tra bytese strin Python 3.


4

Da Cos'è Unicode :

Fondamentalmente, i computer gestiscono solo i numeri. Memorizzano lettere e altri caratteri assegnando un numero a ciascuno.

......

Unicode fornisce un numero univoco per ogni personaggio, qualunque sia la piattaforma, qualunque sia il programma, qualunque sia la lingua.

Quindi, quando un computer rappresenta una stringa, trova i caratteri memorizzati nel computer della stringa attraverso il loro numero Unicode univoco e queste figure sono memorizzate. Ma non puoi scrivere direttamente la stringa su disco o trasmettere la stringa in rete attraverso il loro numero Unicode univoco perché queste cifre sono solo un semplice numero decimale. È necessario codificare la stringa in stringa di byte, ad esempio UTF-8. UTF-8è un personaggio codifica in grado di codificare tutti i possibili caratteri e lo memorizza come caratteri byte (sembra questo ). Quindi la stringa codificata può essere utilizzata ovunque perché UTF-8è quasi supportata ovunque. Quando si apre un file di testo codificatoUTF-8da altri sistemi, il computer lo decodificherà e visualizzerà i caratteri in esso tramite il loro numero Unicode univoco. Quando un browser riceve i dati di stringa codificati UTF-8dalla rete, li decodifica in stringa (presuppone il browser nella UTF-8codifica) e visualizza la stringa.

In python3, puoi trasformare stringa e stringa di byte l'una con l'altra:

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

In una parola, stringa è per essere mostrato agli umani per leggere su un computer e stringa di byte per l'archiviazione su disco e trasmissione dei dati.


1

Unicode è un formato concordato per la rappresentazione binaria di caratteri e vari tipi di formattazione (ad esempio lettere minuscole / maiuscole, nuova riga, ritorno a capo) e altre "cose" (ad esempio emoji). Un computer non è meno in grado di memorizzare una rappresentazione unicode (una serie di bit), sia in memoria che in un file, piuttosto che memorizzare una rappresentazione ASCII (una diversa serie di bit) o ​​qualsiasi altra rappresentazione (serie di bit ).

Affinché la comunicazione abbia luogo, le parti della comunicazione devono concordare quale rappresentazione verrà utilizzata.

Poiché unicode cerca di rappresentare tutti i possibili caratteri (e altre "cose") utilizzati nella comunicazione interumana e tra computer, richiede un numero maggiore di bit per la rappresentazione di molti caratteri (o cose) rispetto ad altri sistemi di rappresentazione che cercare di rappresentare un insieme più limitato di personaggi / cose. Per "semplificare" e forse per adattarsi all'uso storico, la rappresentazione unicode viene quasi esclusivamente convertita in qualche altro sistema di rappresentazione (ad esempio ascii) allo scopo di memorizzare caratteri nei file.

Non è possibile che Unicode non possa essere utilizzato per archiviare caratteri nei file o trasmetterli attraverso qualsiasi canale di comunicazione, semplicemente che non lo è .

Il termine "stringa" non è definito con precisione. "Stringa", nel suo uso comune, si riferisce a un insieme di caratteri / cose. In un computer, quei caratteri possono essere memorizzati in una qualsiasi delle diverse rappresentazioni bit per bit. Una "stringa di byte" è un insieme di caratteri archiviati utilizzando una rappresentazione che utilizza otto bit (otto bit indicati come byte). Poiché in questi giorni i computer utilizzano il sistema unicode (caratteri rappresentati da un numero variabile di byte) per memorizzare i caratteri in memoria e stringhe di byte (caratteri rappresentati da singoli byte) per archiviare i caratteri in file, è necessario utilizzare una conversione prima dei caratteri rappresentati in memoria verrà spostato nella memoria dei file.


0

Diamo una semplice stringa di un carattere 'š'e la codifichiamo in una sequenza di byte:

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

Ai fini di questo esempio, visualizziamo la sequenza di byte nella sua forma binaria:

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

Ora in genere non è possibile decodificare le informazioni senza sapere come sono state codificate. Solo se sai che è utf-8stata utilizzata la codifica del testo, puoi seguire l' algoritmo per decodificare utf-8 e acquisire la stringa originale:

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

È possibile visualizzare 101100001nuovamente il numero binario come stringa:

>>> chr(int('101100001', 2))
'š'

0

I linguaggi Python includono stre bytescome "Tipi predefiniti" standard. In altre parole, sono entrambe le classi. Non credo valga la pena provare a razionalizzare il motivo per cui Python è stato implementato in questo modo.

Detto questo, stre bytessono molto simili tra loro. Entrambi condividono la maggior parte degli stessi metodi. I seguenti metodi sono unici per la strclasse:

casefold
encode
format
format_map
isdecimal
isidentifier
isnumeric
isprintable

I seguenti metodi sono unici per la bytesclasse:

decode
fromhex
hex
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.