#1 Le 21/03/2009, à 03:20
- wlourf
script python : paramètres et accents...
Bonjour,
Avec python 2.6, lors d'un saise avec des accents par raw_input, je peux afficher la valeur saisie après l'avoir décodé avec valeur.decode(sys.stdin.encoding,"strict"), que ce soit avec windows ou avec ubuntu.
Par contre quand je passe un paramètre accentué au script, je n'arrive pas à afficher ce paramètre correctement avec decode(sys.stdin.encoding,"strict") : dédé.txt devient dùdù.txt, ceci seulement sous windows
Avec ça : print fichier.decode("latin-1"), ça fonctionne mais ça ne me semble pas très portable, en plus ça ne fonctionne plus sous ubuntu, forcément!
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys,os
from optparse import OptionParser
parser = OptionParser(usage="usage blabla",version="%prog 22")
(options, args) = parser.parse_args()
fichier=args[0]
print fichier #nok
print fichier.decode(sys.stdin.encoding,"strict")#nok
print fichier.decode("latin-1") #--ok--
f=open(fichier)
print f.read()
Si quelqu'un a une idée ... même si de loin ça ressemble plus à un problème windows (je peux interdire les accents juste pour les utilisateurs de windows mais ce ne serait pas très fairplay!)
Hors ligne
#2 Le 21/03/2009, à 22:59
- zerevo
Re : script python : paramètres et accents...
Désolé je peux pas t'aider j'ai pas windows
Hors ligne
#3 Le 21/03/2009, à 23:06
- Kanor
Re : script python : paramètres et accents...
Ou tu fais un code spécefique pour les utilisateur de windows si je me trompe pas il y a une varaible pour savoir l'os qui tourne
Hors ligne
#4 Le 21/03/2009, à 23:31
- HP
Re : script python : paramètres et accents...
platform ou os.uname (au choix)…
perso, j'ai tendance à privilégier uname parce que c'est difficile de ne pas utiliser import os !
cat /dev/urandom >/dev/null 2>&1 #github
Hors ligne
#5 Le 22/03/2009, à 00:34
- wlourf
Re : script python : paramètres et accents...
ok, merci, je connaissais sys.name ou os.platform qui retournent chacun 6 ou 7 valeurs (pour os.name 'posix', 'nt', 'mac', 'os2', 'ce', 'java', 'riscos'), dans l'absolu, ça ferait 6 ou 7 tests à effectuer mais ça m'étonnerai que mon petit script soit utilisé ailleurs que sur windows ou linux.
Mais pour une même platforme l'encodage de la console peut être modifié par l'utilisateur, c'est pour ça que j'utilise sys.stdout.encoding pour récupérer l'encodage de le console ou tourne le script. Comme je ne suis pas sûr d'avoir bien compris la doc http://docs.python.org/library/sys.html#sys.stdin j'essaierai avec stderr ou stdout mais je ne crois pas que ça changera beaucoup.
Sinon moi aussi je n'ai pas windows (sauf au boulot) mais je ne suis pas sectaire et peut passer des scripts aux windoziens!
Hors ligne
#6 Le 22/03/2009, à 01:41
- zerevo
Re : script python : paramètres et accents...
python probleme.py àéèÖôûÜÛîIFSDFD
àéèÖôûÜÛîIFSDFD
àéèÖôûÜÛîIFSDFD
à éèÃôûÃÃîIFSDFD
Tu as mis le 2eme à nok et le 3eme à ok alors que chez moi j'ai le 2eme qui fonctionne et pas le 3eme.
Mon pc est sous Ubuntu 9.04 et j'ai LANG=fr_FR.UTF-8
Hors ligne
#7 Le 22/03/2009, à 10:58
- HP
Re : script python : paramètres et accents...
Tu as mis le 2eme à nok et le 3eme à ok alors que chez moi j'ai le 2eme qui fonctionne et pas le 3eme.
Évidemment… chez moi aussi .
ok, merci, je connaissais sys.name ou os.platform qui retournent chacun 6 ou 7 valeurs (pour os.name 'posix', 'nt', 'mac', 'os2', 'ce', 'java', 'riscos') […] ça ferait 6 ou 7 tests à effectuer […]
Je répondais juste à Kanor… je n'ai jamais prétendu que c'était LA solution à tes soucis d'encodage .
mais de toute façon si le seul but était de détecter un Windows, ça ne ferait pas 6 tests à effectuer.
Faudra aussi que tu me dises d'où tu sors sys.name et os.platform , désolé moi je ne connais pas…
D'ailleurs os.name je me demande quand est ce qu'il sort 'mac' parce que là sous Mac il me sort 'posix' (ce qui me semble correct… ça dépend ce qu'on attend de cette info !
Dernière modification par HP (Le 22/03/2009, à 11:08)
cat /dev/urandom >/dev/null 2>&1 #github
Hors ligne
#8 Le 22/03/2009, à 12:26
- aleph2
Re : script python : paramètres et accents...
> wlourf
Je ne voudrais pas ébranler tes certitudes, mais ce type de problème est aussi ennuyeux sous *les* Linux que sous *les* Windows.
Le problème de base est le suivant: quelle est le codage de sys.argv ? Il se trouve que sous les Linux, celui-ci dépend des "locale" et que sous les Windows, celui-ci dépend de Windows.
A cela s'ajoute aussi le fait que si un des arguments est un *nom* de fichier, il faut aussi tenir compte de la façon dont celui-ci est codé sur le périphérique qui le contient. (par, ex. CP_ACP connu sous le nom "mbcs" par Python pour une partition fat32, clef usb, ...)
Google > python sys.argv encoding ne manque pas d'informations.
Mon commentaire. Comme la majorité des gens ne comprend rien à rien à tout ce qui touche le codage des caractères, toujours prendre avec des pincettes ce que l'on y trouve.
#9 Le 22/03/2009, à 13:15
- HP
Re : script python : paramètres et accents...
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import sys
charset = 'iso-8859-1'
for i in range(len(sys.argv)):
sys.argv[i] = sys.argv[i].decode(sys.stdin.encoding, 'replace').encode(charset, 'replace')
print('in: %s' % sys.argv[i])
print('out: %s' % sys.argv[i].decode(charset).encode(sys.stdout.encoding))
if 'àéèÖôûÜÛîIFSDFD' in sys.argv:
result = 'on a bien trouvé %(tofind)s dans les arguments' % {'tofind' : '`àéèÖôûÜÛîIFSDFD`'}
print(result.decode(charset).encode(sys.stdout.encoding))
python test.py àéèÖôûÜÛîIFSDFD à߬µπ
in: test.py
out: test.py
in: ?????????IFSDFD
out: àéèÖôûÜÛîIFSDFD
in: ?߬??
out: à߬µ?
on a bien trouvé `àéèÖôûÜÛîIFSDFD` dans les arguments
Voilà quoi…
cat /dev/urandom >/dev/null 2>&1 #github
Hors ligne
#10 Le 22/03/2009, à 17:46
- aleph2
Re : script python : paramètres et accents...
> hp
Le principe de travail est correct ou "n'est pas faux". Tu décodes les arguments en créant un unicode pivot que tu réencodes en iso-8859-1.
Mais...
...la difficulté qui peut survenir vient du fait que, selon les plateformes et/ou leurs configurations et/ou la configuration de Python sous ces plateformes, le codage d'entrée de Python (sys.stdin.encoding) ne correspond pas nécessairement au codage des arguments (sys.argv) de la plateforme, sans compter que le codage des arguments peut être différent du codage du système de fichiers.
Bref, un cas où l'ascii, lingua franca de l'informatique, rend bien service.
#11 Le 22/03/2009, à 17:58
- HP
Re : script python : paramètres et accents...
sans compter que le codage des arguments peut être différent du codage du système de fichiers
Je suis d'accord, et je ne le traitais pas ici… puis faudra que notre ami bosse un peu !
le codage d'entrée de Python (sys.stdin.encoding) ne correspond pas nécessairement au codage des arguments (sys.argv) de la plateforme
çà c'est un peu plus bizarre !
cat /dev/urandom >/dev/null 2>&1 #github
Hors ligne
#12 Le 22/03/2009, à 19:00
- aleph2
Re : script python : paramètres et accents...
> HP
>çà c'est un peu plus bizarre !
Oui. Sous Windows le problème est patent. Je l'ai remarqué hier en effectuant quelques petits tests pour essayer de répondre correctement à wlourf. Sous Windows, en mode console, DOS box, sys.stdin.encoding est cp850 (Py25, 26, 30), ce qui est correct, et pose visiblement problème pour décoder sys.argv, alors que cela fonctionne en utilisant iso-8859-1 (?). J'ai été surpris de ce dysfonctionnement et il me semble que ce n'était pas le cas "auparavant" (version ???). D'un autre côté, ceci est en tel serpent de mer (v. forum des développeurs) que je n'en ai pas été plus étonné que tant.
Sous Linux les choses devraient être plus "propres", bien que, en cherchant sur la toile, on découvre aussi quelques surprises.
#13 Le 02/05/2009, à 17:15
- NicDumZ
Re : script python : paramètres et accents...
#!/usr/bin/env python # -*- coding: iso-8859-1 -*- import sys charset = 'iso-8859-1' for i in range(len(sys.argv)): sys.argv[i] = sys.argv[i].decode(sys.stdin.encoding, 'replace').encode(charset, 'replace') print('in: %s' % sys.argv[i]) print('out: %s' % sys.argv[i].decode(charset).encode(sys.stdout.encoding)) if 'àéèÖôûÜÛîIFSDFD' in sys.argv: result = 'on a bien trouvé %(tofind)s dans les arguments' % {'tofind' : '`àéèÖôûÜÛîIFSDFD`'} print(result.decode(charset).encode(sys.stdout.encoding))
[snip]
Voilà quoi…
Pourquoi forcément réencoder dans un charset intermédiaire? L'unicode est justement fait comme format de données pivot, pour ne pas avoir à se trainer un charset intermédiaire "temporaire"
#!/usr/bin/env python
import sys
for i in range(len(sys.argv)):
sys.argv[i] = sys.argv[i].decode(sys.stdin.encoding, 'replace') # type(sys.argv[i]) == unicode
print(u'in: %s' % sys.argv[i]) # print u' ' pour de l'unicode
print('out: %s' % sys.argv[i].encode(sys.stdout.encoding))
Ce code fait la même chose.
En plus, utiliser un charset intermédiaire pose problème. Dans ton exemple, tu utilises un encodage intermédiaire européen: c'est bien ça fonctionnera pour les caractères accentués occidentaux, quel que soit la locale qu'utilise ton utilisateur.
Cependant, si ton utilisateur est un chinois, ou un Japonais, le fait de réencoder en iso-8859-1 une chaine entrée, disons, en shift-jis ( 'sjis', encodage japonais), lèvera une Erreur:
# "konichiwa", encodé en shift-jis.
hello = '\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd'
# Pour obtenir cette chaine, on aurait aussi bien faire:
# hello = u'こんにちは'.encode('sjis')
# (mais j'imagine que tout le monde n'a pas le support du jap' ici =) )
# Cette chaîne arrive en argument, l'encodage systeme de l'utilisateur est 'sjis'
# on essaie donc de reproduire sys.argv[i].decode(sys.stdin.encoding, 'replace').encode(charset, 'replace') :
en_unicode = hello.decode('sjis') # sys.argv[i].decode(sys.stdin.encoding), OK
en_latin1 = hello.encode('iso-8859-1') #NOK, lève UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-4: ordinal not in range(256)
#Du coup, l'option 'replace' est utilisée, pour ignorer les caractères non encodables en latin1 :
en_latin1 = hello.encode('iso-8859-1', 'replace')
print en_latin1 # Affiche 5 points d'interrogation, au lieu des 5 caractères jap'
Pour résumer, utiliser un encodage intermédiaire plutot que l'unicode, c'est se fermer des possibilités. Plus les différences entre ta variable locale 'charset' et sys.stdin.encoding seront grandes, moins ton texte final ressemblera à ce que l'utilisateur a entré. Il faut donc autant que possible, utiliser de l'unicode en interne.
Hors ligne