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 communic () renvoie 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, je voudrais 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'est à cela que sert la méthode binascii.b2a_qp () , mais quand je l'ai essayée, j'ai de nouveau obtenu le même tableau d'octets:
>>> 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'
Comment puis-je reconvertir la valeur des octets en chaîne? Je veux dire, en utilisant les "batteries" au lieu de le faire manuellement. Et je voudrais que ce soit OK avec Python 3.
python
string
python-3.x
Tomas Sedovic
la source
la source
str(text_bytes)
marche pas ? Cela me semble bizarre.str(text_bytes)
ne peut pas spécifier l'encodage. Selon ce qui se trouve dans text_bytes,text_bytes.decode('cp1250
) `peut entraîner une chaîne très différente detext_bytes.decode('utf-8')
.str
fonction ne se convertit plus en une vraie chaîne. On DOIT dire explicitement un encodage pour une raison quelconque, je suis trop paresseux pour lire pourquoi. Il suffit de le convertirutf-8
et de voir si votre code fonctionne. par exemplevar = var.decode('utf-8')
unicode_text = str(bytestring, character_encoding)
fonctionne comme prévu sur Python 3. Bien qu'ilunicode_text = bytestring.decode(character_encoding)
soit plus préférable d'éviter la confusion avec juste cestr(bytes_obj)
qui produit une représentation textuelle aubytes_obj
lieu de la décoder en texte:str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'
etstr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
Réponses:
Vous devez décoder l'objet bytes pour produire une chaîne:
la source
"windows-1252"
n'est pas non plus fiable (par exemple, pour d'autres versions linguistiques de Windows), ne serait-il pas préférable de l'utilisersys.stdout.encoding
?b"\x80\x02\x03".decode("utf-8")
->UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 0: invalid start byte
.utf-8
conversion est susceptible d'échouer. Voir plutôt la réponse @techtonik (ci-dessous) stackoverflow.com/a/27527728/198536Vous devez décoder la chaîne d'octets et la transformer en chaîne de caractères (Unicode).
Sur Python 2
ou
Sur Python 3
ou
la source
variable = b'hello'
, alorsunicode_text = variable.decode(character_encoding)
Je pense que cette façon est facile:
la source
bytes([112, 52, 52])
- btw bytes est un mauvais nom pour une variable locale exactement parce que c'est un module intégré p3Si vous ne connaissez pas l'encodage, alors pour lire l'entrée binaire en chaîne de manière compatible Python 3 et Python 2, utilisez l'ancien encodage MS-DOS CP437 :
Parce que le codage 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 codages à un octet et UTF-8).Le décodage d'une entrée binaire arbitraire en UTF-8 n'est pas sûr, car vous pouvez obtenir ceci:
La même chose s'applique à
latin-1
, qui était populaire (par défaut?) Pour Python 2. Voir les points manquants dans la mise en page de la page de code - c'est là que Python s'étrangle avec l'infâmeordinal not in range
.MISE À JOUR 20150604 : Il y a des rumeurs selon lesquelles Python 3 a la
surrogateescape
stratégie d'erreur pour encoder des trucs en données binaires sans perte de données et plantages, mais il a besoin de tests de conversion[binary] -> [str] -> [binary]
, pour valider les performances et la fiabilité.MISE À JOUR 20170116 : Merci au commentaire de Nearoo - il y a aussi une possibilité de slash échapper tous les octets inconnus avec le
backslashreplace
gestionnaire d'erreurs. Cela ne fonctionne que pour Python 3, donc même avec cette solution de contournement, vous obtiendrez toujours une sortie incohérente de différentes versions de Python:Voir le support Unicode de Python pour plus de détails.
MISE À JOUR 20170119 : J'ai décidé d'implémenter le décodage d'échappement slash qui fonctionne à la fois pour Python 2 et Python 3. Il devrait être plus lent que la
cp437
solution, mais il devrait produire des résultats identiques sur chaque version de Python.la source
b'\x00\x01\xffsd'.decode('utf-8', 'ignore')
en python 3.b'\x80abc'.decode("utf-8", "backslashreplace")
se traduira par'\\x80abc'
. Ces informations proviennent de la page de documentation unicode qui semble avoir été mise à jour depuis la rédaction de cette réponse.Dans Python 3 , l'encodage par défaut est
"utf-8"
, vous pouvez donc utiliser directement:ce qui équivaut à
D'un autre côté, en Python 2 , l'encodage par défaut est l'encodage de chaîne par défaut. Ainsi, vous devez utiliser:
où
encoding
est l'encodage que vous souhaitez.Remarque: la prise en charge des arguments de mots clés a été ajoutée dans Python 2.7.
la source
Je pense que vous voulez vraiment ceci:
La réponse d'Aaron était correcte, sauf que vous devez savoir quel encodage utiliser. Et je crois que Windows utilise 'windows-1252'. Cela n'aura d'importance que si vous avez des caractères inhabituels (non ASCII) dans votre contenu, mais cela fera une différence.
D'ailleurs, le fait qu'il ne importe est la raison pour laquelle Python déplacé à l' aide de deux types différents pour les données binaires et texte: il ne peut pas convertir par magie entre eux, car il ne sait pas l'encodage à moins que vous le dites! La seule façon que VOUS sauriez est de lire la documentation Windows (ou de la lire ici).
la source
open()
fonction pour les flux de texte ouPopen()
si vous le transmettez,universal_newlines=True
décidez par magie de l'encodage des caractères pour vous (locale.getpreferredencoding(False)
dans Python 3.3+).'latin-1'
est un encodage textuel avec tous les points de code définis, vous pouvez donc l'utiliser pour lire efficacement une chaîne d'octets dans le type de chaîne pris en charge par Python (donc textuellement sur Python 2, dans Unicode pour Python 3).'latin-1'
est un bon moyen d'obtenir du mojibake. Il existe également une substitution magique sur Windows: il est étonnamment difficile de transférer des données d'un processus à un autre, par exempledir
:\xb6
->\x14
(l'exemple à la fin de ma réponse)Définissez universal_newlines sur True, c'est-à-dire
la source
text=True
place deuniversal_newlines=True
.Alors que la réponse de @Aaron Maenpaa fonctionne, un utilisateur a récemment demandé :
Vous pouvez utiliser:
decode()
a un argument standard :la source
.decode()
ces utilisations'utf-8'
peuvent échouer (la sortie de la commande peut utiliser un codage de caractères différent ou même retourner une séquence d'octets indécodable). Bien que si l'entrée est ascii (un sous-ensemble de utf-8), cela.decode()
fonctionne.Pour interpréter une séquence d'octets comme un texte, vous devez connaître le codage de caractères correspondant:
Exemple:
ls
La commande peut produire une sortie qui ne peut pas être interprétée comme du texte. Les noms de fichiers sous Unix peuvent être n'importe quelle séquence d'octets, sauf la barre obliqueb'/'
et zérob'\0'
:Essayer de décoder une telle soupe d'octets en utilisant des augmentations de codage utf-8
UnicodeDecodeError
.Ça peut être pire. Le décodage peut échouer en silence et produire du mojibake si vous utilisez un mauvais encodage incompatible:
Les données sont corrompues mais votre programme ne sait pas qu'une erreur s'est produite.
En général, le codage de caractères à utiliser n'est pas intégré dans la séquence d'octets elle-même. Vous devez communiquer ces informations hors bande. Certains résultats sont plus probables que d'autres et il
chardet
existe donc un module qui peut deviner l'encodage des caractères. Un seul script Python peut utiliser plusieurs encodages de caractères à différents endroits.ls
sortie peut être convertie en une chaîne de caractères en utilisant pythonos.fsdecode()
fonction qui réussit même pour les noms de fichiers indécodables (il utilisesys.getfilesystemencoding()
etsurrogateescape
gestionnaire d'erreurs sur Unix):Pour obtenir les octets d'origine, vous pouvez utiliser
os.fsencode()
.Si vous passez un
universal_newlines=True
paramètre, puissubprocess
utiliselocale.getpreferredencoding(False)
pour décoder les octets, par exemple, il peut êtrecp1252
sous Windows.Pour décoder le flux d'octets à la volée,
io.TextIOWrapper()
pourrait être utilisé: exemple .Différentes commandes peuvent utiliser différents codages de caractères pour leur sortie, par exemple,
dir
la commande interne (cmd
) peut utiliser cp437. Pour décoder sa sortie, vous pouvez passer l'encodage explicitement (Python 3.6+):Les noms de fichiers peuvent différer de
os.listdir()
(qui utilise l'API Windows Unicode), par exemple,'\xb6'
peuvent être remplacés par'\x14'
les mappages de codec cp437 de Pythonb'\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 PowerShell contenant éventuellement des caractères Unicode non ASCII dans une chaîne Pythonla source
Puisque cette question pose réellement sur la
subprocess
sortie, vous avez une approche plus directe disponible carPopen
accepte un mot-clé d' encodage (dans Python 3.6+):La réponse générale pour les autres utilisateurs est de décoder les octets en texte:
Sans argument,
sys.getdefaultencoding()
sera utilisé. Si vos données ne le sont passys.getdefaultencoding()
, vous devez spécifier le codage explicitement dans l'decode
appel:la source
text=True
pour décoder stdin, stdout et stderr en utilisant l'encodage donné (s'il est défini) ou le système par défaut sinon.Popen(['ls', '-l'], stdout=PIPE, text=True)
.ls
sortie à l'aide de l'utf-8
encodage peut échouer (voir l'exemple dans ma réponse de 2016 ).encoding
paramètre est donné, alors letext
paramètre est ignoré.Si vous devez obtenir ce qui suit en essayant
decode()
:Vous pouvez également spécifier le type d'encodage directement dans une distribution:
la source
Lorsque
\r\n
je travaille avec des données de systèmes Windows (avec des fins de ligne), ma réponse estPourquoi? Essayez ceci avec un Input.txt multiligne:
Toutes vos fins de ligne seront doublées (à
\r\r\n
), ce qui entraînera des lignes vides supplémentaires. Les fonctions de lecture de texte de Python normalisent généralement les fins de ligne afin que les chaînes n'utilisent que\n
. Si vous recevez des données binaires d'un système Windows, Python n'a pas la possibilité de le faire. Donc,va répliquer votre fichier d'origine.
la source
.replace("\r\n", "\n")
plus longtemps. C'est la réponse si vous voulez rendre correctement le HTML.J'ai fait une fonction pour nettoyer une liste
la source
.strip
,.replace
,.encode
, etc appels dans une compréhension de liste et seulement sur la liste itérer une fois au lieu de Enumérer les cinq fois.Pour Python 3, c'est une approche beaucoup plus sûre et Pythonique pour convertir de
byte
àstring
:Production:
la source
byte_to_str
", ce qui implique qu'elle renverra une chaîne, mais elle imprime uniquement la valeur convertie et affiche un message d'erreur en cas d'échec (mais ne déclenche pas d'exception). Cette approche est également impythonique et obscurcit labytes.decode
solution que vous avez fournie.From sys - Paramètres et fonctions spécifiques au système :
Pour écrire ou lire des données binaires depuis / vers les flux standard, utilisez le tampon binaire sous-jacent. Par exemple, pour écrire des octets dans stdout, utilisez
sys.stdout.buffer.write(b'abc')
.la source
bytes
valeur résultante .la source
Pour votre cas spécifique de «exécuter une commande shell et obtenir sa sortie sous forme de texte au lieu d'octets», sur Python 3.7, vous devez utiliser
subprocess.run
et passertext=True
(ainsi quecapture_output=True
pour capturer la sortie)text
utilisé pour être appeléuniversal_newlines
, et a été modifié (enfin, aliasé) dans Python 3.7. Si vous souhaitez prendre en charge les versions Python avant 3.7, passez auuniversal_newlines=True
lieu detext=True
la source
Si vous souhaitez convertir des octets, pas seulement une chaîne convertie en octets:
Ce n'est cependant pas très efficace. Cela transformera une image de 2 Mo en 9 Mo.
la source
essaye ça
la source