Как заставить str.translate работать со строками Unicode? - PullRequest
56 голосов
/ 24 августа 2009

У меня есть следующий код:

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)

Который отлично работает для не-юникодных строк:

>>> translate_non_alphanumerics('<foo>!')
'_foo__'

Но не работает для строк 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

Я не могу понять смысл параграфа «Объекты Unicode» в Документах Python 2.6.2 для метода str.translate ().

Как мне заставить эту работу работать со строками Unicode?

Ответы [ 6 ]

56 голосов
/ 24 августа 2009

Версия перевода Unicode требует сопоставления с порядковыми номерами Unicode (которые можно получить для одного символа с ord) с порядковыми числами Unicode. Если вы хотите удалить символы, вы отображаетесь на None.

Я изменил вашу функцию, чтобы создать диктовку, отображающую порядковый номер каждого символа в порядковый номер того, на что вы хотите перевести:

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: Оказывается, что преобразование перевода должно отображаться из порядкового номера Unicode (через ord) в другой порядковый номер Unicode, строку Unicode или None (для удаления). Таким образом, я изменил значение по умолчанию для translate_to, чтобы оно было литералом Unicode. Например:

>>> translate_non_alphanumerics(u'<foo>!', u'bad')
u'badfoobadbad'
7 голосов
/ 01 октября 2013

В этой версии вы можете относительно писать свои письма другим

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)
5 голосов
/ 24 августа 2009

Я предложил следующую комбинацию моей исходной функции и версии Mike , которая работает со строками Unicode и 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)

Обновление : "принудительно" translate_to для Unicode для Unicode translate_table. Спасибо, Майк.

4 голосов
/ 25 августа 2009

Для простого хака, который будет работать как с объектами str, так и с юникодом, преобразовать таблицу перевода в юникод перед запуском 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)

Подвох в том, что он неявно преобразует все объекты str в юникод, выдает ошибки, если to_translate содержит символы не ascii.

0 голосов
/ 10 ноября 2017

Я обнаружил, что где в Python 2.7, с типом str, вы написали бы

import string
table = string.maketrans("123", "abc")
print "135".translate(table)

тогда как с типом unicode вы бы сказали

table = {ord(s): unicode(d) for s, d in zip("123", "abc")}
print u"135".translate(table)

В Python 3.6 вы бы написали

table = {ord(s): d for s, d in zip("123", "abc")}
print("135".translate(table))

может быть, это полезно.

0 голосов
/ 01 ноября 2012

Вместо того, чтобы указывать все символы, которые необходимо заменить, вы также можете просмотреть его наоборот и вместо этого указать только действительные символы, например:

import re

def replace_non_alphanumerics(source, replacement_character='_'):
    result = re.sub("[^_a-zA-Z0-9]", replacement_character, source)

    return result

Это работает как с юникодом, так и с обычными строками, и сохраняет тип (если, очевидно, и replacement_character, и source относятся к одному типу).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...