(Courriels de diversion: <drapant@empeigne-variances.com> <accueillais@mis-godelureau.com> <exacerberait@decoudrez-usages.com> <sermonnes@econduirais-prohibitions.com> <maximaliseriez@gendarmeries-actualiseront.com> <anisette@slip-solidarisa.com> <incite@authentiques-prête.com> <profanes@premonitoires-incarcereriez.com> <fêlerait@longilignes-enjoint.com> <experimentais@dechirerons-desherba.com> )


Bonjour,

J'ai remarqué que le langage libre Python 2 a un comportement particulier face aux données textuelles.

Ce comportement est lié aux différents encodages de caractères utilisés sur différents systèmes voir dans un même système.

J'ai en particulier trouvé un système aux caractéristiques suivantes:
- code source python codé en iso-8859-1
- données bureautiques en unicode
- sorties consoles en cp850.

Le traitement correct consiste donc à faire les bonnes transformations d'encodage là où c'est opportun.

Toutefois, l'écriture sur la console de textes composé de caractères et/ou octets non gérés par la console lève une exception qui arrête le script python, ce qui est un comportement strict qui pour le moins contraste avec le fait que l'on peut faire un print de n'importe quel type de données...

On pourrait vouloir que la console ait un comportement plus tolérant; par exemple: si certains caractères ne peuvent pas être affichés sur la console, alors afficher des caractères de substitution, et continuer.

Ce problème est déjà commenté sur internet, mais je n'arrive pas à trouver de solution satisfaisante:
http://www.afpy.org/python/forum_python/forum_general/0736420857415
http://stackoverflow.com/questions/6788158/handling-unicode-strings-in-windows
http://wiki.python.org/moin/PrintFails


Par ailleurs, j'arrive à reproduire ce problème sous linux, et je crois avoir trouvé un contournement,
mais je me demande s'il peut y avoir des cas où cela ne fonctionne pas (version de python, etc.):
Comment faire pour que ce code soit portable?

Est-ce qu'un connaisseur de python pourrait me donner un avis à ce sujet?
Est-il possible de mettre la rustine de stdout dans un import; comment?

D'avance merci

Donc:
A/ Enregistrer le script situé entre les lignes ciseaux (--8<--):

    -----8<---8<------ début ------8<------
#!/usr/bin/python
# -*- encoding: iso-8859-1 -*-

import sys
import traceback

# Deux exemples de textes pour illustrer les problematiques de caracteres accentues.
pangramme = u"".join ( ( 
    u"sur son \xeele int\xe9rieure, ",
    u"\xe0 c\xf4t\xe9 de l'alc\xf4ve ovo\xefde, ",
    u"o\xf9 les b\xfbches se consument dans l'\xe2tre, ",
    u"ce qui lui permet de penser \xe0 la c\xe6nogen\xe8se de l'\xeatre dont ",
    u"il est question dans la cause ambigu\xeb entendue \xe0 Mo\xff, ",
    u"dans un capharna\xfcm qui, pense-t-il, i",
    u"diminue \xe7\xe0 et l\xe0 la qualit\xe9 de son \u0153uvre." 
    ))

kafka = u"".join(  (
          u"En se r\u00e9veillant un matin apr\u00e8s des r\u00eaves agit\u00e9s, " , 
          u"Gregor Samsa se retrouva, dans son lit, ",
          u"m\u00e9tamorphos\u00e9 en un monstrueux insecte." ) )

fauxTexte = pangramme[0 : 60]

# Simulation d'un code qui affiche des chaines ayant subi des manipulations 
# incontrolees, dans le domaine du typage et de l'encodage:
def maFonctionDefectueuse(texte):
  b = texte.encode('iso-8859-1')
  c = texte.encode('cp850')
  for x in [ c, b, texte]:
    print x

# La Rustine
class maRustineStdout:
  def __init__(self, stream, cp):
    self.stream = stream
    self.cp = cp
  def write (self, data):
    try:
      self.stream.write( data)
    except:
      pile = traceback.format_stack()
      try:
        self.stream.write( data.encode(self.cp, 'replace' ) )
      except:
        self.stream.write( "Ne sait pas ecrire une donnee de type " + str(type ( data )) + "\n"  )
        sys.stderr.write ( "".join(pile) )
        traceback.print_exc(file=sys.stderr)
    

# Ce que l'on ne veut pas
print "\n# Ce que l'on ne veut pas: "
# L'exception arrête l'execution normale
try:
  maFonctionDefectueuse(fauxTexte)
  maFonctionDefectueuse(fauxTexte)
except:
  traceback.print_exc()

# Ce que l'on veut: 
print "\nCe que l'on veut: "
# l'execution continue independament des limitations de la console
sys.stdout = maRustineStdout( sys.__stdout__, 'cp850' )
maFonctionDefectueuse(fauxTexte)
maFonctionDefectueuse(fauxTexte)

    -----8<---8<------ -fin- ------8<------


B.1/ Pour reproduire une console en CP850
     Depuis un terminal que l'on ne souhaite plus utiliser
     # Positionner les locales (Casse la configuration de ce terminal)
     LC_ALL=IBM850
     # Lancer un terminal qui accepte le CP850
     gnome-terminal &
     # Aller dans le menu «Terminal»/«Définir le codage des caractères»/«Occidental IBM850»
     # En passant si besoin, par le sous-menu «Ajouter ou supprimer...»

B.2/ Ou utiliser python dans une console de l'OS Windows.

C/ Lancer le script qui donne la sortie suivante:


python test_encoding.py 

# Ce que l'on ne veut pas: 
sur son île intérieure, à côté de l'alcôve ovoïde, où les bû
sur son ¯le intÚrieure, Ó c¶tÚ de l'alc¶ve ovo´de, o¨ les b¹
Traceback (most recent call last):
  File "test_encoding.py", line 65, in <module>
    maFonctionDefectueuse(fauxTexte)
  File "test_encoding.py", line 41, in maFonctionDefectueuse
    print x
UnicodeEncodeError: 'ascii' codec can't encode character u'\xee' in position 8: ordinal not in range(128)

Ce que l'on veut: 
sur son île intérieure, à côté de l'alcôve ovoïde, où les bû
sur son ¯le intÚrieure, Ó c¶tÚ de l'alc¶ve ovo´de, o¨ les b¹
sur son île intérieure, à côté de l'alcôve ovoïde, où les bû
sur son île intérieure, à côté de l'alcôve ovoïde, où les bû
sur son ¯le intÚrieure, Ó c¶tÚ de l'alc¶ve ovo´de, o¨ les b¹
sur son île intérieure, à côté de l'alcôve ovoïde, où les bû




-----------------------------------------------------------------
Les listes de diffusion du CULTe - Pour une informatique libre
http://www.CULTe.org/listes/
Pour se desabonner:
mailto:linux-31-unsubscribe@CULTe.org?subject=Cliquez_sur_ENVOYER