如何使str.translate与Unicode字符串一起工作?

56 投票
7 回答
35805 浏览
提问于 2025-04-15 13:50

我有以下这段代码:

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)

这段代码对非Unicode字符串效果很好:

>>> 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

我看不懂在Python 2.6.2文档中关于“Unicode对象”的那段话,特别是关于str.translate()方法的部分。

我该如何让这段代码也能处理Unicode字符串呢?

7 个回答

5

我想出了一个结合我自己原来的函数和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一起使用。谢谢你,Mike。

7

在这个版本中,你可以相对地调整一个字母与其他字母之间的关系。

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)
58

Unicode版本的translate函数需要一个映射,这个映射是从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__'

补充:结果发现,转换映射必须是从Unicode编码(通过ord获取)映射到另一个Unicode编码、一个Unicode字符串,或者是None(表示删除)。因此,我把translate_to的默认值改成了一个Unicode字面量。例如:

>>> translate_non_alphanumerics(u'<foo>!', u'bad')
u'badfoobadbad'

撰写回答