web-dev-qa-db-fra.com

Comment faire en sorte que l’interprète python gère correctement les caractères non-ASCII dans les opérations sur les chaînes de caractères?

J'ai une chaîne qui ressemble à ceci:

6Â 918Â 417Â 712

Le moyen le plus simple de couper cette chaîne (si je comprends bien Python) est simplement de dire que la chaîne se trouve dans une variable appelée s, nous obtenons:

s.replace('Â ', '')

Cela devrait faire l'affaire. Mais bien sûr, il se plaint que le caractère non-ASCII '\xc2' dans le fichier blabla.py n'est pas codé.

Je n'ai jamais vraiment compris comment passer d'un encodage à un autre.

Voici le code, il est en fait le même que ci-dessus, mais maintenant il est dans le contexte. Le fichier est enregistré au format UTF-8 dans le bloc-notes et comporte l'en-tête suivant:

#!/usr/bin/python2.4
# -*- coding: utf-8 -*-

Le code:

f = urllib.urlopen(url)

soup = BeautifulSoup(f)

s = soup.find('div', {'id':'main_count'})

#making a print 's' here goes well. it shows 6Â 918Â 417Â 712

s.replace('Â ','')

save_main_count(s)

Cela ne va pas plus loin que s.replace...

100
adergaard

Python 2 utilise ascii comme encodage par défaut pour les fichiers source, ce qui signifie que vous devez spécifier un autre encodage en haut du fichier pour utiliser des caractères unicode non ascii dans les littéraux. Python 3 utilise utf-8 Comme codage par défaut pour les fichiers source. Il s’agit donc d’un problème moins grave.

Voir: http://docs.python.org/tutorial/interpreter.html#source-code-encoding

Pour activer le codage source utf-8, cela irait dans l’une des deux premières lignes:

# -*- coding: utf-8 -*-

Ce qui précède est dans la documentation, mais cela fonctionne aussi:

# coding: utf-8

Considérations supplémentaires:

  • Le fichier source doit également être enregistré en utilisant le codage correct dans votre éditeur de texte.

  • Dans Python 2, le littéral unicode doit être précédé de u, comme dans s.replace(u"Â ", u"") mais dans Python 3 , utilisez simplement des guillemets. Dans Python 2, vous pouvez from __future__ import unicode_literals pour obtenir le comportement Python 3, mais sachez que cela affecte tout le module.

  • s.replace(u"Â ", u"") échouera également si s n'est pas une chaîne unicode.

  • string.replace Renvoie une nouvelle chaîne et n'édite pas à la place, assurez-vous donc que vous utilisez également la valeur de retour

78
Jason S
def removeNonAscii(s): return "".join(filter(lambda x: ord(x)<128, s))

edit: ma première impulsion est toujours d'utiliser un filtre, mais l'expression du générateur est plus efficace en mémoire (et plus courte) ...

def removeNonAscii(s): return "".join(i for i in s if ord(i)<128)

N'oubliez pas que cela est garanti pour fonctionner avec le codage UTF-8 (car le bit le plus fort est défini sur 1 pour tous les octets dans les caractères multi-octets).

156
fortran
>>> unicode_string = u"hello aåbäcö"
>>> unicode_string.encode("ascii", "ignore")
'hello abc'
31
truppo

Le code suivant remplacera tous les caractères ASCII) par des points d'interrogation.

"".join([x if ord(x) < 128 else '?' for x in s])
16
VisioN

Utilisation de Regex:

import re

strip_unicode = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)")
print strip_unicode.sub('', u'6Â 918Â 417Â 712')
6
Akoi Meexx

Bien trop tard pour une réponse, mais la chaîne d'origine était en UTF-8 et '\ xc2\xa0' est en UTF-8 pour NO-BREAK SPACE. Décodez simplement la chaîne d'origine en tant que s.decode('utf-8') (\ xa0 s'affiche sous la forme d'un espace lorsqu'il est décodé de manière incorrecte en tant que Windows-1252 ou latin-1:

Exemple (Python 3)

s = b'6\xc2\xa0918\xc2\xa0417\xc2\xa0712'
print(s.decode('latin-1')) # incorrectly decoded
u = s.decode('utf8') # correctly decoded
print(u)
print(u.replace('\N{NO-BREAK SPACE}','_'))
print(u.replace('\xa0','-')) # \xa0 is Unicode for NO-BREAK SPACE

Sortie

6Â 918Â 417Â 712
6 918 417 712
6_918_417_712
6-918-417-712
5
Mark Tolonen
#!/usr/bin/env python
# -*- coding: utf-8 -*-

s = u"6Â 918Â 417Â 712"
s = s.replace(u"Â", "") 
print s

Ceci imprimera 6 918 417 712

3
Alvin Row

Je sais que c'est un vieux fil, mais je me suis senti obligé de mentionner la méthode de traduction, qui est toujours un bon moyen de remplacer tous les codes de caractère supérieurs à 128 (ou autre si nécessaire).

Utilisation: str. traduire ( tableau [ supprime les caractères])

>>> trans_table = ''.join( [chr(i) for i in range(128)] + [' '] * 128 )

>>> 'Résultat'.translate(trans_table)
'R sultat'
>>> '6Â 918Â 417Â 712'.translate(trans_table)
'6  918  417  712'

À partir de Python 2.6, vous pouvez également définir le tableau sur Aucun et utiliser deletechars pour supprimer les caractères non souhaités, comme indiqué dans les exemples ci-dessous. la documentation standard sur http://docs.python.org/library/stdtypes.html .

Avec les chaînes unicode, la table de traduction n'est pas une chaîne de 256 caractères, mais un dict avec la clé ord (). Quoi qu'il en soit, obtenir une chaîne ascii appropriée à partir d'une chaîne unicode est assez simple, en utilisant la méthode mentionnée par truppo ci-dessus, à savoir: unicode_string.encode ("ascii", "ignore")

En résumé, si pour une raison quelconque vous devez absolument obtenir une chaîne ascii (par exemple, lorsque vous déclenchez une exception standard avec raise Exception, ascii_message), vous pouvez utiliser la fonction suivante:

trans_table = ''.join( [chr(i) for i in range(128)] + ['?'] * 128 )
def ascii(s):
    if isinstance(s, unicode):
        return s.encode('ascii', 'replace')
    else:
        return s.translate(trans_table)

La bonne chose à traduire est que vous pouvez réellement convertir les caractères accentués en pertinents caractères ascii non accentués au lieu de simplement les supprimer ou de les remplacer par '?'. Ceci est souvent utile, par exemple à des fins d’indexation.

2
Louis LC
s.replace(u'Â ', '')              # u before string is important

et faites votre .py fichier unicode.

1
SilentGhost

C'est un sale bidouillage, mais peut fonctionner.

s2 = ""
for i in s:
    if ord(i) < 128:
        s2 += i
1
Corey D

Pour ce que cela valait, mon jeu de caractères était utf-8 et j'avais inclus le classique "# -*- coding: utf-8 -*-" ligne.

Cependant, j'ai découvert que je ne possédais pas Universal Newlines lors de la lecture de ces données à partir d'une page Web.

Mon texte avait deux mots, séparés par "\r\n ". Je me séparais seulement du \n et remplacer le "\n".

Une fois que j'ai parcouru et vu le jeu de caractères en question, j'ai réalisé l'erreur.

Donc, cela pourrait aussi être dans le jeu de caractères ASCII , mais un caractère auquel vous ne vous attendiez pas.

0
Glen