print - python transform string to byte




Converti i byte in una stringa? (11)

Sto usando questo codice per ottenere l'output standard da un programma esterno:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]

Il metodo communicate () restituisce una matrice di byte:

>>> command_stdout
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2\n'

Tuttavia, mi piacerebbe lavorare con l'output come una normale stringa di Python. In modo che potessi stamparlo così:

>>> print(command_stdout)
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2

Ho pensato che fosse quello il metodo binascii.b2a_qp() , ma quando l'ho provato, ho ottenuto di nuovo lo stesso array di byte:

>>> binascii.b2a_qp(command_stdout)
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2\n'

Qualcuno sa come convertire il valore dei byte in stringa? Voglio dire, usare le "batterie" invece di farlo manualmente. E mi piacerebbe che fosse ok con Python 3.


È necessario decodificare l'oggetto bytes per produrre una stringa:

>>> b"abcde"
b'abcde'

# utf-8 is used here because it is a very common encoding, but you
# need to use the encoding your data is actually in.
>>> b"abcde".decode("utf-8") 
'abcde'

È necessario decodificare la stringa di byte e trasformarla in una stringa di carattere (unicode).

b'hello'.decode(encoding)

o

str(b'hello', encoding)

Dato che questa domanda è in realtà una domanda sull'output dei subprocess , hai un approccio più diretto dal momento che Popen accetta una parola chiave di encoding (in Python 3.6+):

>>> from subprocess import Popen, PIPE
>>> text = Popen(['ls', '-l'], stdout=PIPE, encoding='utf-8').communicate()[0]
>>> type(text)
str
>>> print(text)
total 0
-rw-r--r-- 1 wim badger 0 May 31 12:45 some_file.txt

La risposta generale per gli altri utenti è la decodifica dei byte in testo:

>>> b'abcde'.decode()
'abcde'

Senza argomenti, verrà utilizzato sys.getdefaultencoding() . Se i tuoi dati non sono sys.getdefaultencoding() , devi specificare esplicitamente la codifica nella chiamata di decode :

>>> b'caf\xe9'.decode('cp1250')
'café'

Ho fatto una funzione per pulire una lista

def cleanLists(self, lista):
    lista = [x.strip() for x in lista]
    lista = [x.replace('\n', '') for x in lista]
    lista = [x.replace('\b', '') for x in lista]
    lista = [x.encode('utf8') for x in lista]
    lista = [x.decode('utf8') for x in lista]

    return lista

Mentre la risposta di @Aaron Maenpaa funziona, un utente ha chiesto di recente

C'è un modo più semplice? 'fhand.read (). decode ("ASCII")' [...] È così lungo!

Puoi usare

command_stdout.decode()

decode() ha un argomento standard

codecs.decode(obj, encoding='utf-8', errors='strict')


Penso che quello che vuoi veramente sia questo:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')

La risposta di Aaron era corretta, tranne per il fatto che devi sapere quale codifica usare. E credo che Windows usi 'windows-1252'. Importerà solo se nel tuo contenuto ci sono caratteri insoliti (non ASCII), ma poi farà la differenza.

A proposito, il fatto che sia importante è il motivo per cui Python si è trasferito a usare due tipi diversi per dati binari e di testo: non può convertire magicamente tra di loro perché non conosce la codifica a meno che tu non lo dica! L'unico modo che potresti sapere è leggere la documentazione di Windows (o leggerla qui).


Per Python 3, questo è un approccio molto più sicuro e Pythonic per convertire da byte a string :

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): #check if its in bytes
        print(bytes_or_str.decode('utf-8'))
    else:
        print("Object not of byte type")

byte_to_str(b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2\n')

Produzione:

total 0
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2

Per interpretare una sequenza di byte come un testo, devi conoscere la codifica dei caratteri corrispondente:

unicode_text = bytestring.decode(character_encoding)

Esempio:

>>> b'\xc2\xb5'.decode('utf-8')
'µ'

ls comando ls può produrre un output che non può essere interpretato come testo. I nomi dei file su Unix possono essere qualsiasi sequenza di byte tranne la barra b'/' e zero b'\0' :

>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()

Cercando di decodificare tale zuppa di byte usando la codifica utf-8 solleva UnicodeDecodeError .

Può essere peggio La decodifica potrebbe fallire silenziosamente e produrre mojibake se si utilizza una codifica incompatibile errata:

>>> '—'.encode('utf-8').decode('cp1252')
'—'

I dati sono corrotti ma il tuo programma rimane inconsapevole che si è verificato un errore.

In generale, quale codifica dei caratteri utilizzare non è incorporata nella sequenza di byte stessa. Devi comunicare queste informazioni fuori banda. Alcuni risultati sono più probabili di altri e quindi esiste un modulo chardet che può indovinare la codifica dei caratteri. Un singolo script Python può utilizzare più codifiche di caratteri in luoghi diversi.

ls output può essere convertito in una stringa Python utilizzando la funzione os.fsdecode() che riesce anche per i nomi di file non sys.getfilesystemencoding() utilizza sys.getfilesystemencoding() e gestore di errori surrogateescape su Unix):

import os
import subprocess

output = os.fsdecode(subprocess.check_output('ls'))

Per ottenere i byte originali, è possibile utilizzare os.fsencode() .

Se si passa universal_newlines=True parametro, il subprocess utilizza locale.getpreferredencoding(False) per decodificare i byte, ad esempio, può essere cp1252 su Windows.

Per decodificare il flusso di byte al volo, si può io.TextIOWrapper() : example .

Comandi diversi possono utilizzare codifiche di caratteri diverse per il loro output, ad esempio, il comando interno di dir ( cmd ) può usare cp437. Per decodificare l'output, è possibile passare esplicitamente la codifica (Python 3.6+):

output = subprocess.check_output('dir', shell=True, encoding='cp437')

I nomi dei file possono essere diversi da os.listdir() (che utilizza API Unicode di Windows), ad esempio, '\xb6' può essere sostituito con '\x14' -Python's cp437 codec maps b'\x14' per controllare il carattere U + 0014 invece di U + 00B6 (¶). Per supportare i nomi di file con caratteri Unicode arbitrari, vedere Decodificare l'output di poweshell che contiene eventualmente caratteri unicode non ascii in una stringa python


Se dovresti ottenere quanto segue provando la decode() :

AttributeError: 'str' object has no attribute 'decode'

Puoi anche specificare il tipo di codifica direttamente in un cast:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'

Se non si conosce la codifica, quindi per leggere l'input binario nella stringa in modo compatibile con Python 3 e Python 2, utilizzare la codifica cp437 MS-DOS cp437 :

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('cp437'))

Poiché la codifica è sconosciuta, si aspettano che i simboli non inglesi traducano in caratteri di cp437 (i caratteri inglesi non sono tradotti perché corrispondono nella maggior parte delle codifiche a byte singolo e UTF-8).

Decodificare l'input binario arbitrario in UTF-8 non è sicuro, perché potresti ottenere questo:

>>> b'\x00\x01\xffsd'.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid
start byte

Lo stesso vale per latin-1 , che era popolare (predefinito?) Per Python 2. Vedi i punti mancanti in Codepage Layout - è dove Python soffoca con il famigerato ordinal not in range .

AGGIORNAMENTO 20150604 : Ci sono voci secondo cui Python 3 ha una strategia di errore surrogateescape per codificare materiale in dati binari senza perdita di dati e arresti anomali, ma necessita di test di conversione [binary] -> [str] -> [binary] per convalidare sia le prestazioni che l'affidabilità.

AGGIORNAMENTI 20170116 : Grazie al commento di Nearoo - c'è anche la possibilità di eliminare tutti i byte sconosciuti con il gestore degli errori di backslashreplace . Funziona solo con Python 3, quindi anche con questa soluzione alternativa otterrai comunque risultati incoerenti da diverse versioni di Python:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('utf-8', 'backslashreplace'))

Vedi https://docs.python.org/3/howto/unicode.html#python-s-unicode-support per i dettagli.

AGGIORNAMENTO 20170119 : Ho deciso di implementare la decodifica di escape di slash che funziona sia per Python 2 che per Python 3. Dovrebbe essere più cp437 soluzione cp437 , ma dovrebbe produrre risultati identici su ogni versione di Python.

# --- preparation

import codecs

def slashescape(err):
    """ codecs error handler. err is UnicodeDecode instance. return
    a tuple with a replacement for the unencodable part of the input
    and a position where encoding should continue"""
    #print err, dir(err), err.start, err.end, err.object[:err.start]
    thebyte = err.object[err.start:err.end]
    repl = u'\\x'+hex(ord(thebyte))[2:]
    return (repl, err.end)

codecs.register_error('slashescape', slashescape)

# --- processing

stream = [b'\x80abc']

lines = []
for line in stream:
    lines.append(line.decode('utf-8', 'slashescape'))

def toString(string):    
    try:
        return v.decode("utf-8")
    except ValueError:
        return string

b = b'97.080.500'
s = '97.080.500'
print(toString(b))
print(toString(s))




python-3.x