Comment convertir un fichier au format Unicode en ASCII à l'aide de Python?
Question
J'utilise un outil tiers qui génère un fichier au format Unicode. Cependant, je préfère que ce soit en ASCII. L'outil ne dispose pas de paramètres pour modifier le format de fichier.
Quel est le meilleur moyen de convertir le format de fichier entier à l'aide de Python?
La solution
Vous pouvez convertir le fichier assez facilement en utilisant la fonction unicode
, mais vous rencontrerez des problèmes avec les caractères Unicode sans équivalent ASCII direct.
Ce blog recommande le unicodedata
module, qui semble prendre en charge la conversion approximative des caractères sans transfert direct valeurs ASCII correspondantes, par exemple
>>> title = u"Klüft skräms inför på fédéral électoral große"
est généralement converti en
Klft skrms infr p fdral lectoral groe
ce qui est assez faux. Cependant, en utilisant le module unicodedata ??code>, le résultat peut être beaucoup plus proche du texte d'origine:
>>> import unicodedata
>>> unicodedata.normalize('NFKD', title).encode('ascii','ignore')
'Kluft skrams infor pa federal electoral groe'
Autres conseils
Je pense que le problème est plus profond que vous ne le réalisez . Changer simplement le fichier d'Unicode en ASCII est facile, cependant, convertir tous les caractères Unicode en des équivalents ASCII raisonnables (de nombreuses lettres ne sont pas disponibles dans les deux encodages) en est un autre.
Ce didacticiel Python Unicode peut vous donner une meilleure idée de ce qu'il advient des chaînes Unicode traduites en ASCII: http://www.reportlab.com/i18n/python_unicode_tutorial.html
Voici une citation utile du site:
Python 1.6 obtient également un "unicode" fonction intégrée, à laquelle vous pouvez spécifiez le codage:
> >>> unicode('hello') u'hello'
> >>> unicode('hello', 'ascii') u'hello'
> >>> unicode('hello', 'iso-8859-1') u'hello'
> >>>
Tous les trois retournent le même chose, puisque les personnages dans 'Bonjour' sont communs aux trois encodages.
Maintenant encodons quelque chose avec un Accent européen, qui est en dehors de ASCII. Ce que vous voyez sur une console peut dépend de votre système d'exploitation lieu; Windows me permet de taper ISO-Latin-1.
> >>> a = unicode('André','latin-1')
> >>> a u'Andr\202'
Si vous ne pouvez pas taper une lettre aiguë e, vous pouvez entrer la chaîne 'Andr \ 202', ce qui est sans ambiguïté.
Unicode supporte tous les courants des opérations telles que l'itération et scission. Nous ne les verrons pas ici.
À propos, il s'agit d'une commande linux iconv
pour effectuer ce type de travail.
iconv -f utf8 -t ascii <input.txt >output.txt
Voici un code simple (et stupide) permettant d’encoder la traduction. Je suppose (mais vous ne devriez pas) que le fichier d'entrée est en UTF-16 (Windows appelle cela simplement 'Unicode').
input_codec = 'UTF-16'
output_codec = 'ASCII'
unicode_file = open('filename')
unicode_data = unicode_file.read().decode(input_codec)
ascii_file = open('new filename', 'w')
ascii_file.write(unicode_data.write(unicode_data.encode(output_codec)))
Notez que cela ne fonctionnera pas si le fichier Unicode contient des caractères qui ne sont pas également des caractères ASCII. Vous pouvez effectuer les opérations suivantes pour transformer des caractères non reconnus en '?':
ascii_file.write(unicode_data.write(unicode_data.encode(output_codec, 'replace')))
Découvrez la documentation pour des choix plus simples. Si vous avez besoin de faire quelque chose de plus sophistiqué, vous pouvez consulter le marteau UNICODE à l'adresse le livre de recettes Python.
Comme ceci:
uc = open(filename).read().decode('utf8')
ascii = uc.decode('ascii')
Notez cependant que cela échouera avec une exception UnicodeDecodeError
s'il existe des caractères qui ne peuvent pas être convertis en ASCII.
EDIT: Comme Pete Karl vient de le dire, il n’existe pas de correspondance individuelle entre Unicode et ASCII. Ainsi, certains caractères ne peuvent tout simplement pas être convertis de manière à préserver les informations. De plus, l'ASCII standard est plus ou moins un sous-ensemble de l'UTF-8, vous n'avez donc même pas besoin de décoder.
Pour mon problème où je voulais juste ignorer les caractères non-ascii et ne sortir que la sortie ascii, la solution ci-dessous a très bien fonctionné:
import unicodedata
input = open(filename).read().decode('UTF-16')
output = unicodedata.normalize('NFKD', input).encode('ASCII', 'ignore')
Il est important de noter qu’il n’existe pas de format de fichier «Unicode». Unicode peut être codé en octets de différentes manières. Le plus souvent UTF-8 ou UTF-16. Vous aurez besoin de savoir lequel de votre outil tiers produit en sortie. Une fois que vous savez cela, la conversion entre différents encodages est assez facile:
in_file = open("myfile.txt", "rb")
out_file = open("mynewfile.txt", "wb")
in_byte_string = in_file.read()
unicode_string = bytestring.decode('UTF-16')
out_byte_string = unicode_string.encode('ASCII')
out_file.write(out_byte_string)
out_file.close()
Comme indiqué dans les autres réponses, vous souhaiterez probablement fournir un gestionnaire d'erreurs à la méthode d'encodage. Utiliser 'remplacer' comme gestionnaire d'erreurs est simple, mais modifiera votre texte s'il contient des caractères qui ne peuvent pas être représentés en ASCII.
Comme d'autres afficheurs l'ont noté, ASCII est un sous-ensemble d'Unicode.
Cependant si vous:
- avoir une application héritée
- vous ne contrôlez pas le code de cette application
- vous êtes certain que votre entrée tombe dans le sous-ensemble ASCII
Ensuite, l'exemple ci-dessous montre comment procéder:
mystring = u'bar'
type(mystring)
<type 'unicode'>
myasciistring = (mystring.encode('ASCII'))
type(myasciistring)
<type 'str'>