J'ai le code suivant:
import string
def translate_non_alphanumerics(to_translate, translate_to='_'):
not_letters_or_digits = u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~'
translate_table = string.maketrans(not_letters_or_digits,
translate_to
*len(not_letters_or_digits))
return to_translate.translate(translate_table)
Ce qui fonctionne très bien pour les chaînes non-unicode:
>>> translate_non_alphanumerics('<foo>!')
'_foo__'
Mais échoue pour les chaînes unicode:
>>> translate_non_alphanumerics(u'<foo>!')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in translate_non_alphanumerics
TypeError: character mapping must return integer, None or unicode
Je ne peux pas comprendre le paragraphe "Objets Unicode" dans la documentation Python 2.6.2 pour la méthode str.translate ().
Comment puis-je faire ce travail pour les chaînes Unicode?
La version Unicode de translate nécessite un mappage d'ordinaux Unicode (que vous pouvez récupérer pour un seul caractère avec ord
) en ordinaux Unicode. Si vous souhaitez supprimer des caractères, vous mappez sur None
.
J'ai changé votre fonction pour construire un dict mappant l'ordinal de chaque caractère à l'ordinal de ce que vous voulez traduire:
def translate_non_alphanumerics(to_translate, translate_to=u'_'):
not_letters_or_digits = u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~'
translate_table = dict((ord(char), translate_to) for char in not_letters_or_digits)
return to_translate.translate(translate_table)
>>> translate_non_alphanumerics(u'<foo>!')
u'_foo__'
edit: Il s'avère que le mappage de traduction doit être mappé de l'ordinal Unicode (via ord
) sur un autre ordinal Unicode, une chaîne Unicode ou Aucune (à supprimer). J'ai donc changé la valeur par défaut pour translate_to
en un littéral Unicode. Par exemple:
>>> translate_non_alphanumerics(u'<foo>!', u'bad')
u'badfoobadbad'
Dans cette version, vous pouvez faire ses lettres à d’autres
def trans(to_translate):
tabin = u'привет'
tabout = u'тевирп'
tabin = [ord(char) for char in tabin]
translate_table = dict(Zip(tabin, tabout))
return to_translate.translate(translate_table)
J'ai trouvé la combinaison suivante de ma fonction d'origine et de la version de Mike qui fonctionne avec les chaînes Unicode et ASCII:
def translate_non_alphanumerics(to_translate, translate_to=u'_'):
not_letters_or_digits = u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~'
if isinstance(to_translate, unicode):
translate_table = dict((ord(char), unicode(translate_to))
for char in not_letters_or_digits)
else:
assert isinstance(to_translate, str)
translate_table = string.maketrans(not_letters_or_digits,
translate_to
*len(not_letters_or_digits))
return to_translate.translate(translate_table)
Update: "contraint" translate_to
à unicode pour le code unicode translate_table
. Merci Mike.
Pour un hack simple qui fonctionnera à la fois sur les objets str et unicode, Convertira la table de traduction en unicode avant d'exécuter translate ():
import string
def translate_non_alphanumerics(to_translate, translate_to='_'):
not_letters_or_digits = u'!"#%\'()*+,-./:;<=>?@[\]^_`{|}~'
translate_table = string.maketrans(not_letters_or_digits,
translate_to
*len(not_letters_or_digits))
translate_table = translate_table.decode("latin-1")
return to_translate.translate(translate_table)
Le problème ici est qu’il convertira implicitement tous les objets str en unicode, en générant des erreurs si to_translate contient des caractères non ascii.
Au lieu d'avoir à spécifier tous les caractères devant être remplacés, vous pouvez également le voir dans l'autre sens et spécifier uniquement les caractères valides, comme suit:
import re
def replace_non_alphanumerics(source, replacement_character='_'):
result = re.sub("[^_a-zA-Z0-9]", replacement_character, source)
return result
Cela fonctionne avec les chaînes unicode et normales et conserve le type (si le replacement_character
et le source
sont du même type, évidemment).
J'ai trouvé que dans python 2.7, avec le type str
, vous écririez
import string
table = string.maketrans("123", "abc")
print "135".translate(table)
alors qu'avec le type unicode
vous diriez
table = {ord(s): unicode(d) for s, d in Zip("123", "abc")}
print u"135".translate(table)
En python 3.6, vous écririez
table = {ord(s): d for s, d in Zip("123", "abc")}
print("135".translate(table))
c'est peut-être utile.