Écrire en unicode dans un fichier via stdout

Le
Laurent Claessens
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.

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

a=u"éà"
print a
fin de l'exemple ==
==

Si je lance normalement ce script, j'obtiens ceci dans la console :
éà

parfait.

Par contre si je le lance en détournant 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à c'est moins parfait.

Afin d'éviter ce problème, j'ai eu l'idée de détourner
systématiquement tout les sys.stdout vers une classe à moi qui encode
avant d'écrire :

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

import sys

class MyStdOut(object):
def __init__(self):
self.old_stdout=sys.stdout
def write(self,x):
try:
x=x.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=u"éà"
sys.stdout=MyStdOut()
print a

-- fin de l'exemple -

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

Bonne aprème
Laurent
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Laurent Claessens
Le #23156421
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.
Michel Claveau - MVP
Le #23158151
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
Bruno Piguet
Le #23159561
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.
p.hanser
Le #23170261
On 26 fév, 05:57, "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 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
Laurent Claessens
Le #23175161
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
jmfauth
Le #23180611
On Feb 25, 2:46 pm, Laurent Claessens
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.
jmfauth
Le #23180601
On Mar 2, 1:45 pm, "p.hanser"
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, ...).
Publicité
Poster une réponse
Anonyme