如何让str.translate使用Unicode字符串?

时间:2009-08-24 18:52:53

标签: python unicode string

我有以下代码:

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

对于str.translate()方法,我无法理解Python 2.6.2 docs中关于“Unicode对象”的段落。

如何使这项工作适用于Unicode字符串?

7 个答案:

答案 0 :(得分:56)

Unicode版本的translate需要从Unicode序列(您可以检索具有ord的单个字符)到Unicode序列的映射。如果要删除字符,请映射到None

我改变了你的函数来构建一个dict,将每个字符的序数映射到你想要翻译成的序数:

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字符串或无(删除)。因此,我将translate_to的默认值更改为Unicode文字。例如:

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

答案 1 :(得分: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)

答案 2 :(得分: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 translate_table进行解码。谢谢迈克。

答案 3 :(得分:4)

对于一个适用于str和unicode对象的简单hack, 在运行translate()之前将转换表转换为unicode:

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对象转换为unicode, 如果to_translate包含非ascii字符,则抛出错误。

答案 4 :(得分:0)

不必指定需要替换的所有字符,您也可以反过来查看它,而是只指定有效字符,如下所示:

import re

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

    return result

这适用于unicode和常规字符串,并保留类型(如果replacement_charactersource属于同一类型,显然也是如此。)

答案 5 :(得分:0)

我发现在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))

也许这很有帮助。

答案 6 :(得分:0)

与这里的其他人相比,我有一个独特的问题。首先,我知道我的字符串中可能包含Unicode字符。 (感谢在Mac上使用电子邮件...)但是常见的字符之一是Emdash AKA u“ \ u2014”字符,需要将其转换(返回)为两个破折号AKA“-”。可能找到的其他字符是单字符翻译,因此它们与其他解决方案相似。

首先,我为Emdash创建了一个字典。对于这些,我使用一个简单的string.replace()进行转换。其他类似的字符也可以在这里处理。

uTranslateDict = {
    u"\u2014": "--", # Emdash
}

然后我为1:1翻译创建了一个元组。这些通过内置的string.translate()进行。

uTranslateTuple = [(u"\u2010", "-"),  # Hyphen
                   (u"\u2013", "-"),  # Endash
                   (u"\u2018", "'"),  # Left single quote => single quote
                   (u"\u2019", "'"),  # Right single quote => single quote
                   (u"\u201a", "'"),  # Single Low-9 quote => single quote
                   (u"\u201b", "'"),  # Single High-Reversed-9 quote => single quote
                   (u"\u201c", '"'),  # Left double quote => double quote
                   (u"\u201d", '"'),  # Right double quote => double quote
                   (u"\u201e", '"'),  # Double Low-9 quote => double quote
                   (u"\u201f", '"'),  # Double High-Reversed-9 quote => double quote
                   (u"\u2022", "*"),  # Bullet
]

然后是功能。

def uTranslate(uToTranslate):
    uTranslateTable = dict((ord(From), unicode(To)) for From, To in uTranslateTuple)
    for c in uTranslateDict.keys():
        uIntermediateStr = uToTranslate.decode("utf-8").replace(c, uTranslateDict[c])
    return uIntermediateStr.translate(uTranslateTable)

因为我知道输入字符串的格式,所以我不必担心两种类型的输入字符串。