Convertir des octets en chaîne?

j'utilise ce code pour obtenir la sortie standard d'un programme externe:

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

la méthode communicate() retourne un tableau d'octets:

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

cependant, j'aimerais travailler avec la sortie comme une chaîne Python normale. Pour que je puisse l'imprimer comme ceci:

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

je pensais que c'était ce que le binascii.b2a_qp () méthode est pour, mais quand je l'ai essayé, j'ai obtenu le même byte tableau de nouveau:

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

est-ce que quelqu'un sait comment convertir la valeur des octets en chaîne? Je veux dire, utiliser les "batteries" au lieu de le faire manuellement. Et J'aimerais que ce soit ok avec Python 3.

1337
demandé sur martineau 2009-03-03 15:23:01
la source

16 ответов

vous devez décoder l'objet bytes pour produire une chaîne de caractères:

>>> 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'
2199
répondu Aaron Maenpaa 2015-07-24 21:14:12
la source

je pense que cette voie est facile:

bytes = [112, 52, 52]
"".join(map(chr, bytes))
>> p44
122
répondu Sisso 2014-09-01 20:24:12
la source

vous devez décoder la chaîne byte et la transformer en une chaîne de caractères (unicode).

b'hello'.decode(encoding)

ou

str(b'hello', encoding)
103
répondu dF. 2009-03-03 15:39:09
la source

si vous ne connaissez pas l'encodage, alors pour lire l'entrée binaire en chaîne de Python 3 et Python 2 de manière compatible, utilisez L'ancien MS-DOS cp437 encodage:

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

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

parce que l'encodage est inconnu, attendez-vous à ce que les symboles non-anglais se traduisent en caractères de cp437 (les caractères anglais ne sont pas traduits, car ils correspondent dans la plupart des encodages simples et UTF-8).

décodage des entrées binaires arbitraires en UTF-8 est dangereux, parce que vous pouvez obtenir ceci:

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

La même chose s'applique à latin-1 , qui a été populaire (par défaut?) pour Python 2. Voir les points manquants dans codepage Layout - c'est là que Python s'étouffe avec infâme ordinal not in range .

mise à jour 20150604 : il y a des rumeurs que Python 3 a "15197092020" stratégie d'erreur pour encoder des trucs dans des données binaires sans perte de données et se bloque, mais il nécessite des tests de conversion [binary] -> [str] -> [binary] pour valider à la fois la performance et la fiabilité.

mise à jour 20170116 : grâce au commentaire de Nearoo - il y a également une possibilité de slash escape tous les octets inconnus avec le gestionnaire d'erreurs backslashreplace . Cela ne fonctionne que pour Python 3, donc même avec ce contournement, vous obtiendrez toujours des sorties incohérentes de différentes versions de 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'))

voir https://docs.python.org/3/howto/unicode.html#python-s-unicode-support pour plus de détails.

mise à jour 20170119 : j'ai décidé d'implémenter slash escaping decode qui fonctionne à la fois pour Python 2 et Python 3. Il devrait être plus lent que la solution cp437 , mais il devrait produire résultats identiques sur chaque version de 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'))
58
répondu anatoly techtonik 2017-01-19 17:12:02
la source

en Python 3 , l'encodage par défaut est "utf-8" , de sorte que vous pouvez utiliser directement:

b'hello'.decode()

qui est l'équivalent de

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

d'un autre côté, en Python 2 , encodage par défaut à la chaîne de caractères par défaut encodage. Vous devez donc utiliser:

b'hello'.decode(encoding)

encoding est l'encodage que vous voulez.

Note: le support des arguments de mots clés a été ajouté dans Python 2.7.

35
répondu lmiguelvargasf 2018-06-11 00:48:51
la source

je pense que ce que vous voulez réellement est ceci:

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

la réponse D'Aaron était correcte, sauf que vous devez savoir quel encodage utiliser. Et je crois que Windows utilise "windows-1252". Cela ne sera important que si vous avez des caractères inhabituels (non-ascii) dans votre contenu, mais cela fera une différence.

soit dit en passant, le fait qu'il importe est la raison pour laquelle Python est passé à l'utilisation de deux types différents pour le binaire et le texte data: il ne peut pas se convertir comme par magie entre eux parce qu'il ne connaît pas l'encodage à moins que vous le disiez! La seule façon de le savoir est de lire la documentation de Windows (ou de la lire ici).

33
répondu mcherm 2011-07-18 23:51:15
la source

mettre universal_newlines à True, i.e.

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]
26
répondu ContextSwitch 2014-01-21 19:47:48
la source

tandis que la réponse de @Aaron Maenpaa just works, a user a récemment demandé

Est-il plus simple? 'fhand.lire.)(decode ("ASCII")" [...] C'est tellement long!

vous pouvez utiliser

command_stdout.decode()

decode() a une standard "argument 151950920"

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

15
répondu serv-inc 2017-05-23 14:55:03
la source

Pour interpréter une séquence d'octets comme un texte, vous devez connaître le codage de caractères correspondant:

unicode_text = bytestring.decode(character_encoding)

exemple:

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

ls peut produire une sortie qui ne peut pas être interprétée comme du texte. Les noms de fichier sur Unix peut être n'importe quelle séquence d'octets sauf slash b'/' et zéro b'"151980920"' :

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

en Essayant de décoder ces octets de la soupe à l'aide de l'encodage utf-8 soulève UnicodeDecodeError .

ça peut être pire. Le décodage peut échouer silencieusement et produire mojibake si vous utilisez un mauvais encodage incompatible:

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

les données sont corrompues mais votre programme reste ignorant qu'un échec a eu lieu.

en général, le type de caractère codant à utiliser n'est pas incorporé dans la séquence octet elle-même. Vous devez communiquer cette information hors bande. Certains résultats sont plus susceptibles que les d'autres et donc chardet module existe qui peut deviner l'encodage de caractère. Un seul script Python peut utiliser des encodages de caractères multiples à différents endroits.


ls la sortie peut être convertie en une chaîne de Python en utilisant os.fsdecode() fonction qui réussit même pour indécodable nom de fichier (il utilise sys.getfilesystemencoding() et surrogateescape gestionnaire d'erreur sur Unix):

import os
import subprocess

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

pour obtenir les octets originaux, vous pouvez utiliser os.fsencode() .

Si vous passez "1519160920 paramètre" puis subprocess utilise locale.getpreferredencoding(False) pour décoder des octets par exemple, il peut être cp1252 sur Windows.

Pour décoder le flux d'octets à la volée, io.TextIOWrapper() peut-être utilisé: exemple .

différentes commandes peuvent utiliser des encodages de caractères différents pour leur sortie par exemple, dir commande interne ( cmd ) peut utiliser cp437. Pour décoder son sortie, vous pouvez passer l'encodage explicitement (Python 3.6+):

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

les noms de fichiers peuvent différer de os.listdir() (qui utilise Windows API Unicode) par exemple, '\xb6' peut être remplacé par '\x14' - Python's cp437 codec maps b'\x14' pour contrôler le caractère U+0014 au lieu de U+00B6 (¶). Pour prendre en charge les noms de fichiers avec des caractères Unicode arbitraires, voir décoder la sortie poweshell contenant éventuellement des caractères unicode non ascii dans une chaîne de caractères python

10
répondu jfs 2017-05-23 15:26:31
la source

puisque cette question Est en fait poser des questions sur subprocess sortie, vous avez une approche plus directe Disponible depuis Popen accepte un encodage mot-clé (en 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 réponse générale pour les autres utilisateurs est de décoder octets de texte:

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

sans argument, sys.getdefaultencoding() sera utilisé. Si vos données ne sont pas sys.getdefaultencoding() , alors vous devez spécifier le codage explicitement dans le decode appel:

>>> b'caf\xe9'.decode('cp1250')
'café'
6
répondu wim 2018-05-31 20:52:19
la source

Si vous devriez obtenir le texte suivant en tentant de decode() :

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

vous pouvez également spécifier le type d'encodage directement dans un cast:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'
5
répondu Broper 2017-11-22 07:20:55
la source

j'ai fait une fonction pour nettoyer une liste

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
4
répondu eafloresf 2017-03-09 13:03:11
la source

quand je travaille avec des données des systèmes Windows (avec des fins de ligne \r\n ), ma réponse est

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

pourquoi? Essayez ceci avec une entrée multiligne.txt:

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

toutes les fins de ligne seront doublées (à \r\r\n ), ce qui donnera des lignes vides supplémentaires. Les fonctions de lecture de texte de Python normalisent habituellement les fins de ligne de sorte que les chaînes n'utilisent que \n . Si vous recevez des données binaires d'un système Windows, Python n'a pas de une chance de le faire. Ainsi,

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

répliquera votre fichier original.

2
répondu bers 2018-03-16 16:28:25
la source

pour Python 3, c'est une approche beaucoup plus sûre et Pythonic pour passer de byte à 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')

sortie:

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
1
répondu Inconnu 2017-01-18 10:21:09
la source
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))
0
répondu Leonardo Filipe 2018-06-04 01:44:45
la source

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

pour écrire ou lire des données binaires à partir/vers les flux standards, utilisez le tampon binaire sous-jacent. Par exemple, pour écrire des octets à stdout, utilisez sys.la sortie standard stdout.tampon.Ecrire (b'ABC').

-1
répondu Zhichang Yu 2014-01-11 11:15:18
la source

Autres questions sur python string python-3.x