Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Écrire en unicode dans un fichier via stdout

7 réponses
Avatar
Laurent Claessens
Bonjour

Bon, le titre n'est pas tr=E8s clair, mais il contient les mots clefs.

J'ai des caract=E8res unicodes dans des cha=EEnes partout dans mon
programme, et je veux d=E9tourner la sortie vers un fichier.

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Exemple minimum =
=3D=3D=3D=3D=3D=3D=3D=3D
#! /usr/bin/python
# -*- coding: utf8 -*-

a=3Du"=E9=E0"
print a
=3D=3D=3D=3D=3D=3D=3D=3D=3D fin de l'exemple =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D

Si je lance normalement ce script, j'obtiens ceci dans la console :
=E9=E0

parfait.

Par contre si je le lance en d=E9tournant la sortie vers un fichier:

14:36:05 ~/script >$ ./test.py >test.txt

Traceback (most recent call last):
File "./test.py", line 5, in <module>
print a
UnicodeEncodeError: 'ascii' codec can't encode characters in position
0-1: ordinal not in range(128)

L=E0 c'est moins parfait.

Afin d'=E9viter ce probl=E8me, j'ai eu l'id=E9e de d=E9tourner
syst=E9matiquement tout les sys.stdout vers une classe =E0 moi qui encode
avant d'=E9crire :

-------------------- Exemple moins minimum -----------
#! /usr/bin/python
# -*- coding: utf8 -*-

import sys

class MyStdOut(object):
def __init__(self):
self.old_stdout=3Dsys.stdout
def write(self,x):
try:
x=3Dx.encode("utf8")
except UnicodeEncodeError:
print "You should never see this if you do not mix unicode
and str !"
pass
self.old_stdout.write(x)


a=3Du"=E9=E0"
sys.stdout=3DMyStdOut()
print a

----------------------- fin de l'exemple ----------

Ce syst=E8me fonctionne bien pour cet exemple minimum.
Est-ce que c'est une bonne fa=E7on de faire ? Est-ce qu'il y a des
meilleurs conseils ?

Bonne apr=E8me
Laurent

7 réponses

Avatar
Laurent Claessens
Je me permet d'ajouter un mot à ma question :

Sur des exemples réels, je remarque qu'il faut améliorer la classe
MyStdOut en

class MyStdOut(object):
def __init__(self):
self.old_stdout=sys.stdout
def write(self,x):
try:
if isinstance(x,unicode):
x=x.encode("utf8")
except (UnicodeEncodeError,UnicodeDecodeError):
sys.stderr.write("This should not happen !")
self.old_stdout.write(x)

Ainsi si le script mélange des str et des unicodes, seuls les unicodes
sont encodés.
Avatar
Michel Claveau - MVP
Bonjour !

Il me semble que, si tu as un str (au lieu d'Unicode), il va être
écrit tel quel, quel que soit l'encodage. Or, rien ne dit que cet encodage
sera UTF-8 (ça dépend d'où vient le str).
Donc, il y a risque d'avoir des mélanges d'encodages.

@+
--
MCi
Avatar
Bruno Piguet
Le 25/02/2011 14:46, Laurent Claessens a écrit :
[...]
Est-ce qu'il y a des meilleurs conseils ?




A une question proche que j'ai posé sur ce forum en septembre dernier
("print : comment avoir une conversion d'encodage non bloquante ?"), il
n'y a pas eu de réponse après celle proposant ce système : créer son
propre object, qui va remplacer sys.stdout et qui utilise le filehandle
de sys.stdout original.

Bruno.
Avatar
p.hanser
On 26 fév, 05:57, "Michel Claveau -
MVP" wrote:
Bonjour !

Il me semble que, si tu as un str (au lieu d'Unicode), il va être
écrit tel quel, quel que soit l'encodage. Or, rien ne dit que cet encod age
sera UTF-8 (ça dépend d'où vient le str).
Donc, il y a risque d'avoir des mélanges d'encodages.

@+
--
MCi



c'est surement très propre avec une classe et des vérifications,
et tout et tout...

quand on veut faire vite, on peut faire ceci

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

en tête de fichier, ce qui passe stdout inconditionnellement en utf-8

--
Pierre
Avatar
Laurent Claessens
Le 26/02/2011 05:57, Michel Claveau - MVP a écrit :
Bonjour !

Il me semble que, si tu as un str (au lieu d'Unicode), il va être
écrit tel quel, quel que soit l'encodage. Or, rien ne dit que cet encodage
sera UTF-8 (ça dépend d'où vient le str).
Donc, il y a risque d'avoir des mélanges d'encodages.



Disons que dans mon cas je fais bien attention à encoder en utf8 tout ce
qui rentre dans mon programme et à ne déclarer les chaines sous la forme
x = u"éà"

De plus, les entrées du programme que j'ai en tête sont les noms des
répertoire de mon ordinateur (tout bien en utf8).

Donc je suis certain que tout est du utf8 ou de l'ascii (ce que retourne
les def __str__(self)).

Maintenant c'est vrai que si je passe mon programme à un utilisateur qui
encode ses noms de répertoires en autre chose que ascii ou utf8, alors
je ne peux pas garantir la portabilité.
Cependant, pour autant que je le sache, il n'y a *aucun* moyen de
garantir la portabilité au niveau des encodages.


Je tiens mes informations de ce document-ci, dont j'essaie de suivre les
recommandations à la lettre :
http://dl.afpy.org/pycon-fr-09/Comprendre_les_erreurs_unicode.pdf

Bonne journée
Laurent
Avatar
jmfauth
On Feb 25, 2:46 pm, Laurent Claessens wrote:
Bonjour

Bon, le titre n'est pas très clair, mais il contient les mots clefs.

J'ai des caractères unicodes dans des chaînes partout dans mon
programme, et je veux détourner la sortie vers un fichier.



...

Un 'unicode' n'a pas, du point de vue utilisateur, de
codage intrinsèque et doit toujours être encodé ou
décodé pour être conforme au dispositif qui l'émet ou
l'accueille; que ce soit une console, un clavier, une
base de données, un fichier, une imprimante, ...
Ceci est inhérent à 'unicode' et est indépendant de
de tout langage ou plateforme.

Python (2 ou 3) ne déroge pas à cette règle. Le bon usage
est de le faire explicitement.

Exemples (Py 2.7) avec une console comme dispositif de sortie:

import sys
u = u'abcéà€'
print u.encode(sys.stdout.encoding, 'replace')

fontionne dans tous les cas.


Si pour une raison (compréhensible), sys.stdout.encoding
n'est pas défini, c'est alors à l'utilisateur de choisir
le codage qui lui convient.

import sys
u = u'abcàé€'
if sys.stdout.encoding is None:
usedcoding = 'cp1252'
else:
usedcoding = sys.stdout.encoding
print u.encode(usedcoding, 'replace')

fonctionne aussi dans tous les cas.

Ditto pour sys.stderr. En Python 3, c'est
un peut différent, mais le principe est le même.
Avatar
jmfauth
On Mar 2, 1:45 pm, "p.hanser" wrote:
On 26 fév, 05:57, "Michel Claveau -


quand on veut faire vite, on peut faire ceci

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

en tête de fichier, ce qui passe stdout inconditionnellement en utf-8





Le "defaultencoding" est une variable (opaque) utilisée
en interne par Python. Elle est et doit être 'ascii' en
Python 2 et 'utf-8' en Python 3.

Autrement Python peut tout simplement ne pas fonctionner
correctement (hashing, dict, ...).