Vra

Ek gebruik hierdie kode om standaarduitvoer vanaf 'n eksterne program te kry:

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

Die communicate() metode gee 'n skikking van grepe terug:

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

Ek wil egter graag met die uitvoer werk as 'n normale Python-string.Sodat ek dit so kan druk:

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

Ek het gedink dis wat die binascii.b2a_qp() metode is vir, maar toe ek dit probeer het, het ek weer dieselfde byte-skikking gekry:

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

Weet iemand hoe om die grepe-waarde terug na string om te skakel?Ek bedoel, gebruik die "batterye" in plaas daarvan om dit met die hand te doen.En ek wil graag hê dit moet reg wees met Python 3.

Was dit nuttig?

Oplossing

Jy moet die grepe voorwerp te ontsyfer 'n string te produseer:

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

Ander wenke

Ek dink hierdie manier is maklik:

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

Jy moet die byte string ontsyfer en draai dit in 'n karakter (Unicode) string.

Op Python 2

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

Op Python 3

encoding = 'utf-8'
str(b'hello', encoding)

As jy nie die enkodering weet, dan na binêre insette in string lees in Python 3 en Python 2 versoenbaar manier, gebruik ou MS-DOS cp437 enkodering:

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

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

As gevolg encoding is onbekend, verwag nie-Engelse simbole te vertaal na karakters van cp437 (Engels karakters is nie vertaal, want hulle pas in die meeste enkele byte enkoderings en UTF-8).

Dekodering arbitrêre binêre insette te UTF-8 is onveilig, want jy kan dit kry:

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

Dieselfde geld vir latin-1, wat gewild was (standaard?) Vir Python 2. Sien die vermiste punte in CODE uitleg -. dit is waar Python verstik met berugte ordinal not in range

UPDATE 20150604 :. Daar is gerugte dat Python 3 fout strategie surrogateescape vir kodering dinge in binêre data sonder verlies en ineenstortings data, maar dit moet omskakeling toetse [binary] -> [str] -> [binary] om beide prestasie en betroubaarheid te bevestig

UPDATE 20170116 : Dankie om kommentaar te lewer deur Nearoo - daar is ook 'n moontlikheid te streep ontsnap al onbekend grepe met backslashreplace fout hanteerder. Dit werk net vir Python 3, so selfs met hierdie tydelike oplossing sal jy nog kry teenstrydig uitset van verskillende Python weergawes:

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

https: //docs.python. org / 3 / howto / unicode.html # python-s-Unicode-ondersteuning vir meer inligting.

UPDATE 20170119 : Ek het besluit om te implementeer streep ontsnap dekodeer wat werk vir beide Python 2 en Python 3. Dit moet stadiger dat cp437 oplossing wees, maar dit moet produseer identiese resultate op elke Python weergawe.

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

In Python 3 , die verstek enkodering is "utf-8", sodat jy kan direk gebruik:

b'hello'.decode()

wat gelykstaande is aan

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

Aan die ander kant, in Python 2 , enkodering standaard van die standaard string enkodering. So, moet jy gebruik:

b'hello'.decode(encoding)

waar encoding is die enkodering jy wil.

Nota: ondersteuning vir navraag argumente is in Python 2.7 bygevoeg.

Ek dink wat jy eintlik wil hê, is dit:

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

Aaron se antwoord korrek was nie, behalwe dat jy nodig het om te weet watter enkodering om te gebruik. En ek glo dat Windows gebruik 'vensters-1252. Dit sal net saak of jy 'n paar ongewone (nie-ASCII) karakters in jou inhoud, maar dan sal dit 'n verskil te maak.

By the way, die feit dat dit nie saak is die rede dat Python verskuif na die gebruik van twee verskillende tipes vir binêre en teks data: kan dit nie mettertyd omskep tussen hulle, omdat dit nie die enkodering weet nie, tensy jy dit vertel ! Die enigste manier waarop jy wil weet is om die Windows dokumentasie lees (of lees dit hier).

Stel universal_newlines om True, d.w.z.

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

Hoewel antwoord @Aaron Maenpaa se net werk, 'n gebruiker onlangs gevra :

  

Is daar enige meer eenvoudig weg? 'Fhand.read (). Ontsyfer ( "ASCII")' [...] Dit is so lank!

Jy kan gebruik:

command_stdout.decode()

decode() het 'n standaard argument :

  

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

Om 'n byte -volgorde as 'n teks te interpreteer, moet u die ooreenstemmende karakterkodering ken:

unicode_text = bytestring.decode(character_encoding)

Voorbeeld:

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

ls opdrag kan uitvoer produseer wat nie as teks geïnterpreteer kan word nie.Lêernaam op UNIX kan enige volgorde van grepe wees, behalwe Slash b'/' en nulb'\0':

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

Probeer om so 'n greepsop te dekodeer deur gebruik te maak van utf-8 enkodering verhoog UnicodeDecodeError.

Dit kan erger wees.Die dekodering kan stilweg misluk en produseer mojibakas jy 'n verkeerde onversoenbare enkodering gebruik:

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

Die data is beskadig, maar u program bly nie bewus daarvan dat 'n mislukking plaasgevind het nie.

Oor die algemeen, watter karakterkodering om te gebruik, is nie in die greepvolgorde self ingebed nie.Jy moet hierdie inligting buite die band kommunikeer.Sommige uitkomste is meer waarskynlik as ander en daarom chardet module bestaan ​​wat kan raai die karakterkodering.'n Enkele Python-skrip kan veelvuldige karakterenkoderings op verskillende plekke gebruik.


ls uitset kan omgeskakel word na 'n Python-string met behulp van os.fsdecode()funksie wat slaag selfs vir Ondankbare lêernaam (dit gebruiksys.getfilesystemencoding() en surrogateescape Fouthanteerder op Unix):

import os
import subprocess

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

Om die oorspronklike grepe te kry, kan jy gebruik os.fsencode().

As jy slaag universal_newlines=True parameter dan subprocess gebruikelocale.getpreferredencoding(False) grepe te dekodeer, bv. kan dit weescp1252 op Windows.

Om die greepstroom on-the-fly te dekodeer,io.TextIOWrapper()kan gebruik word: voorbeeld.

Verskillende opdragte kan verskillende karakterkoderings gebruik vir hul uitset, bv dir interne opdrag (cmd) kan cp437 gebruik.Om die uitset daarvan te dekodeer, kan u die kodering eksplisiet deurgee (Python 3.6+):

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

Die lêername kan verskil van os.listdir() (wat Windows Unicode API gebruik) bv '\xb6' kan vervang word met '\x14'—Python se CP437 Codec -kaarte b'\x14' Om karakter U+0014 te beheer in plaas van U+00b6 (¶).Om lêername met arbitrêre Unicode-karakters te ondersteun, sien Dekodeer poweshell-uitvoer wat moontlik nie-ascii unicode-karakters bevat in 'n luislangstring

Sedert hierdie vraag is eintlik vra oor subprocess uitset, jy het 'n meer direkte benadering beskikbaar sedert Popen n enkodering navraag (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

Die algemene antwoord vir ander gebruikers is om dekodeer grepe om teks:

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

Met geen argument, sys.getdefaultencoding() gebruik sal word. As jou data nie sys.getdefaultencoding(), dan moet jy die enkodering uitdruklik spesifiseer in die decode oproep:

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

As jy die volgende deur te probeer decode() moet kry:

  

AttributeError: "str 'n voorwerp het geen kenmerk 'dekodeer'

Jy kan ook spesifiseer die tipe kodering reguit in 'n cast:

>>> my_byte_str
b'Hello World'

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

By die werk met data uit Windows-stelsels (met \r\n lyn eindpunte), my antwoord is

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

Hoekom? Probeer dit met 'n multi input.txt:

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

Al jou lyn eindpunte sal verdubbel (tot \r\r\n), wat lei tot ekstra leë lyne. -Teks lees funksies Python se gewoonlik normaliseer lyn eindpunte sodat snare gebruik net \n. As jy binêre data ontvang van 'n Windows-stelsel, beteken Python nie 'n kans om dit te doen. So,

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

sal jou oorspronklike lêer te herhaal.

Ek het 'n funksie om 'n lys skoon

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

Vir Python 3, dit is 'n baie veiliger en Pythonic benadering te omskep van byte om 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')

Uitgawe:

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

As jy wil enige grepe omskep, nie net string omgeskakel word na grepe:

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 nie baie doeltreffend nie, maar. Dit sal 'n 2 MB prent te verander na 9 MB.

Van http://docs.python.org/3/library/sys. html ,

Om te skryf of lees binêre data van / na die standaard strome, gebruik die onderliggende binêre buffer. Byvoorbeeld, om grepe te stdout skryf, gebruik sys.stdout.buffer.write(b'abc').

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top