Byte converteren naar een string

Ik gebruik deze code om standaarduitvoer van een extern programma te krijgen:

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

De methode communication() retourneert een array van bytes:

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

Ik wil echter graag met de uitvoer werken als een normale Python-string. Zodat ik het zo kan afdrukken:

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

Ik dacht dat de binascii.b2a_qp() methode is voor, maar toen ik het probeerde, kreeg ik weer dezelfde byte-array:

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

Hoe converteer ik de bytes-waarde terug naar string? Ik bedoel, de “batterijen” gebruiken in plaats van het handmatig te doen. En ik zou graag willen dat het goed gaat met Python 3.


Antwoord 1, autoriteit 100%

Je moet het bytes-object decoderen om een ​​string te produceren:

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

Antwoord 2, autoriteit 6%

Je moet de bytetekenreeks decoderen en omzetten in een tekenreeks (Unicode).

Op Python 2

encoding = 'utf-8'
'hello'.decode(encoding)

of

unicode('hello', encoding)

Op Python 3

encoding = 'utf-8'
b'hello'.decode(encoding)

of

str(b'hello', encoding)

Antwoord 3, autoriteit 5%

Ik denk dat deze manier makkelijk is:

>>> bytes_data = [112, 52, 52]
>>> "".join(map(chr, bytes_data))
'p44'

Antwoord 4, autoriteit 2%

Als je de codering niet kent, gebruik dan de oude MS-DOS CP437-codering:

PY3K = sys.version_info >= (3, 0)
lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('cp437'))

Omdat de codering onbekend is, kunt u verwachten dat niet-Engelse symbolen worden vertaald naar tekens van cp437 (Engelse tekens worden niet vertaald, omdat ze overeenkomen in de meeste enkelbyte-coderingen en UTF-8).

Het decoderen van willekeurige binaire invoer naar UTF-8 is onveilig, omdat u dit kunt krijgen:

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

Hetzelfde geldt voor latin-1, dat populair was (de standaard?) voor Python 2. Zie de ontbrekende punten in Codepagina-indeling – het is waar Python zich verslikt met de beruchte ordinal not in range.

UPDATE 20150604: er gaan geruchten dat Python 3 de surrogateescape-foutstrategie heeft voor het coderen van dingen in binaire gegevens zonder gegevensverlies en crashes, maar het heeft conversietests nodig, [binary] -> [str] -> [binary], om zowel de prestaties als de betrouwbaarheid te valideren.

UPDATE 20170116: dankzij commentaar van Nearoo – er is ook een mogelijkheid om alle onbekende bytes te slashen met de fouthandler backslashreplace. Dat werkt alleen voor Python 3, dus zelfs met deze tijdelijke oplossing krijg je nog steeds inconsistente uitvoer van verschillende Python-versies:

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

Zie Unicode-ondersteuning van Python voor details.

UPDATE 20170119: ik besloot slash-escaping-decodering te implementeren die werkt voor zowel Python 2 als Python 3. Het zou langzamer moeten zijn dan de cp437-oplossing, maar het zou identieke resultaten moeten opleveren voor elke Python-versie.

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

Antwoord 5, autoriteit 2%

In Python 3 is de standaardcodering "utf-8", zodat u direct het volgende kunt gebruiken:

b'hello'.decode()

wat gelijk is aan

b'hello'.decode(encoding="utf-8")

Aan de andere kant, in Python 2, codering standaard ingesteld op de standaard tekenreekscodering. U moet dus het volgende gebruiken:

b'hello'.decode(encoding)

waarbij encoding de gewenste codering is.

Opmerking: ondersteuning voor trefwoordargumenten is toegevoegd in Python 2.7.


Antwoord 6

Ik denk dat je dit echt wilt:

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

Aaron’s antwoord was correct, behalve dat je moet weten welke codering je moet gebruiken. En ik geloof dat Windows ‘windows-1252’ gebruikt. Het maakt alleen uit of je ongebruikelijke (niet-ASCII) tekens in je inhoud hebt, maar dan zal het een verschil maken.

Trouwens, het feit dat het doet is de reden dat Python twee verschillende typen is gaan gebruiken voor binaire en tekstgegevens: het kan niet op magische wijze tussen beide typen, omdat het dat niet doet. t weet de codering, tenzij je het vertelt! De enige manier die JIJ zou weten, is door de Windows-documentatie te lezen (of hier te lezen).


Antwoord 7

Stel universal_newlines in op True, d.w.z.

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]

Antwoord 8

Als u een bytereeks als tekst wilt interpreteren, moet u de kennen
overeenkomstige tekencodering:

unicode_text = bytestring.decode(character_encoding)

Voorbeeld:

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

De opdracht

ls kan uitvoer produceren die niet als tekst kan worden geïnterpreteerd. Bestandsnamen
op Unix kan elke reeks bytes zijn, behalve slash b'/' en nul
b'\0':

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

Proberen dergelijke bytesoep te decoderen met utf-8-codering verhoogt UnicodeDecodeError.

Het kan erger. Het decoderen kan geruisloos mislukken en mojibake produceren
als u een verkeerde incompatibele codering gebruikt:

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

De gegevens zijn beschadigd, maar uw programma weet niet dat er een fout is opgetreden
heeft plaatsgevonden.

Over het algemeen is de te gebruiken tekencodering niet ingebed in de bytereeks zelf. U moet deze informatie out-of-band communiceren. Sommige uitkomsten zijn waarschijnlijker dan andere en daarom bestaat er een chardet-module die de tekencodering kan raden. Een enkel Python-script kan meerdere tekencoderingen op verschillende plaatsen gebruiken.


ls-uitvoer kan worden geconverteerd naar een Python-tekenreeks met behulp van os.fsdecode()
functie die zelfs werkt voor ondecodeerbaar
bestandsnamen
(het gebruikt
sys.getfilesystemencoding() en surrogateescape foutafhandeling op
Unix):

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

Om de originele bytes te krijgen, kunt u os.fsencode() gebruiken.

Als u de parameter universal_newlines=True doorgeeft, gebruikt subprocess
locale.getpreferredencoding(False) om bytes te decoderen kan bijv.
cp1252 op Windows.

Om de bytestream on-the-fly te decoderen,
io.TextIOWrapper()
kan worden gebruikt: voorbeeld.

Verschillende opdrachten kunnen verschillende tekencoderingen gebruiken voor hun
uitvoer bijv., dir interne opdracht (cmd) kan cp437 gebruiken. Om zijn . te decoderen
uitvoer, kunt u de codering expliciet doorgeven (Python 3.6+):

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

De bestandsnamen kunnen verschillen van os.listdir() (die Windows gebruikt)
Unicode API) bijv. '\xb6' kan worden vervangen door '\x14' Python’s
cp437 codec wijst b'\x14' toe om teken U+0014 te besturen in plaats van
U+00B6 ( ). Om bestandsnamen met willekeurige Unicode-tekens te ondersteunen, zie Decodeer PowerShell-uitvoer die mogelijk niet-ASCII Unicode-tekens bevat in een Python-tekenreeks


Antwoord 9

Aangezien deze vraag eigenlijk gaat over uitvoer van subprocess, heb je meer directe benaderingen beschikbaar. De modernste zou zijn met behulp van subprocess.check_output en text=True (Python 3.7+) doorgeven om stdout automatisch te decoderen met behulp van de standaard systeemcodering:

text = subprocess.check_output(["ls", "-l"], text=True)

Voor Python 3.6 accepteert Popen een codering zoekwoord:

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

Het algemene antwoord op de vraag in de titel, als je niet te maken hebt met uitvoer van subprocessen, is om bytes te decoderen naar tekst:

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

Zonder argument, sys.getdefaultencoding() zal worden gebruikt. Als uw gegevens niet sys.getdefaultencoding() zijn, moet u de codering expliciet specificeren in de decode oproep:

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

Antwoord 10

Hoewel @Aaron Maenpaa’s antwoord gewoon werkt, een gebruiker onlangs gesteld:

Is er een meer eenvoudige manier? ‘fhand.read().decode(“ASCII”)’ […] Het is zo lang!

U kunt gebruiken:

command_stdout.decode()

decode() heeft een standaard argument:

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


Antwoord 11

Als je het volgende zou moeten krijgen door decode() te proberen:

AttributeError: ‘str’ object heeft geen attribuut ‘decode’

Je kunt het coderingstype ook rechtstreeks in een cast specificeren:

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

Antwoord 12

Ik heb een functie gemaakt om een ​​lijst op te schonen

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

Antwoord 13

Bij het werken met gegevens van Windows-systemen (met \r\n regeleindes), is mijn antwoord

String = Bytes.decode("utf-8").replace("\r\n", "\n")

Waarom? Probeer dit met een invoer.txt met meerdere regels:

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)

Al je regeleindes worden verdubbeld (naar \r\r\n), wat leidt tot extra lege regels. De tekst-leesfuncties van Python normaliseren regeleindes, zodat strings alleen \n gebruiken. Als u binaire gegevens van een Windows-systeem ontvangt, heeft Python geen kans om dat te doen. Dus,

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)

repliceert uw originele bestand.


Antwoord 14

Voor Python 3 is dit een veel veiligere en Pythonische benadering om van byte naar string te converteren:

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): # Check if it's 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')

Uitvoer:

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

Antwoord 15

Voor uw specifieke geval van “voer een shell-opdracht uit en krijg de uitvoer als tekst in plaats van bytes”, op Python 3.7, moet u subprocess.run en geef text=True door ( evenals capture_output=True om de uitvoer vast te leggen)

command_result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
command_result.stdout  # is a `str` containing your program's stdout

text heette vroeger universal_newlines, en is gewijzigd (nou ja, alias) in Python 3.7. Als u Python-versies vóór 3.7 wilt ondersteunen, geeft u universal_newlines=True op in plaats van text=True


Antwoord 16

Van sys Systeemspecifieke parameters en functies:

Gebruik de onderliggende binaire buffer om binaire gegevens van/naar de standaardstreams te schrijven of te lezen. Om bijvoorbeeld bytes naar stdout te schrijven, gebruikt u sys.stdout.buffer.write(b'abc').


Antwoord 17

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

Antwoord 18

Als je bytes wilt converteren, niet alleen strings die zijn geconverteerd naar bytes:

with open("bytesfile", "rb") as infile:
    str = base64.b85encode(imageFile.read())
with open("bytesfile", "rb") as infile:
    str2 = json.dumps(list(infile.read()))

Dit is echter niet erg efficiënt. Het verandert een afbeelding van 2 MB in 9 MB.


Antwoord 19

probeer dit

bytes.fromhex('c3a9').decode('utf-8') 

Antwoord 20

Probeer deze eens te gebruiken; deze functie negeert alle niet-tekenset (zoals utf-8) binaire bestanden en retourneert een schone tekenreeks. Het is getest voor python3.6 en hoger.

def bin2str(text, encoding = 'utf-8'):
    """Converts a binary to Unicode string by removing all non Unicode char
    text: binary string to work on
    encoding: output encoding *utf-8"""
    return text.decode(encoding, 'ignore')

Hier neemt de functie het binaire bestand en decodeert het (converteert binaire gegevens naar tekens met behulp van de voorgedefinieerde tekenset van Python en het argument ignore negeert alle niet-tekensetgegevens van uw binaire bestand en retourneert uiteindelijk uw gewenste string waarde.

Als je niet zeker bent van de codering, gebruik dan sys.getdefaultencoding() om de standaardcodering van je apparaat te krijgen.


Antwoord 21

Decoderen met .decode(). Hiermee wordt de string gedecodeerd. Geef 'utf-8') door als de waarde aan de binnenkant.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

14 − nine =

Other episodes