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

Python 如何让str.translate使用Unicode字符串?,python,unicode,string,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,

我有以下代码:

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)
导入字符串
def translate_非字母数字(to_translate,translate_to=''):
不是字母或数字=u'!"#%\'()*+,-./:;?@[\]^_`{|}~'
translate\u table=string.maketrans(不是字母或数字,
翻译成
*len(不是字母或数字)
返回到_translate.translate(translate_表)
这对于非unicode字符串非常有效:

>>> translate_non_alphanumerics('<foo>!')
'_foo__'
>>> 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字符串失败:

>>> translate_non_alphanumerics('<foo>!')
'_foo__'
>>> 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
>>翻译非字母数字(u'!')
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第5行,翻译为非字母数字
TypeError:字符映射必须返回整数、无或unicode
我无法理解str.translate()方法中关于“Unicode对象”的段落


如何对Unicode字符串执行此操作?

Unicode版本的translate需要从Unicode序数(您可以使用检索单个字符)到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和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)
def translate_非字母数字(to_translate,translate_to=u''):
不是字母或数字=u'!“#%\'()*+,-./:@[\]^_`{|}~'
如果isinstance(转换为unicode):
translate_table=dict((ord(字符),unicode(translate_to))
对于非字母或数字形式的字符)
其他:
断言isinstance(要翻译,str)
translate\u table=string.maketrans(不是字母或数字,
翻译成
*len(不是字母或数字)
返回到_translate.translate(translate_表)

更新:“强制”将unicode
translate\u表
转换为unicode。感谢Mike。

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

导入字符串
def translate_非字母数字(to_translate,translate_to=''):
不是字母或数字=u'!"#%\'()*+,-./:;?@[\]^_`{|}~'
translate\u table=string.maketrans(不是字母或数字,
翻译成
*len(不是字母或数字)
翻译表格=翻译表格。解码(“拉丁语-1”)
返回到_translate.translate(translate_表)
这里需要注意的是,它将隐式地将所有str对象转换为unicode,
如果to_translate包含非ascii字符,则引发错误。

您不必指定所有需要替换的字符,也可以通过另一种方式查看,而只指定有效字符,如下所示:

import re

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

    return result

这适用于unicode和常规字符串,并保留类型(如果
替换字符
源代码
显然是同一类型)。

在此版本中,您可以相对地将一个人的字母与另一个人的字母进行转换

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)

我发现在Python2.7中,使用类型
str
,您可以编写

import string
table = string.maketrans("123", "abc")
print "135".translate(table)
table = {ord(s): d for s, d in zip("123", "abc")}
print("135".translate(table))
而对于type
unicode
你会说

table = {ord(s): unicode(d) for s, d in zip("123", "abc")}
print u"135".translate(table)
在Python3.6中,您可以编写

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

也许这会有帮助。

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

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

uTranslateDict = {
    u"\u2014": "--", # Emdash
}
然后我为1:1的翻译创建了一个元组。这些代码通过string.translate()内置

然后是函数

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)

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

我建议您强制将translate\u转换为Unicode版本的Unicode,否则如果您将Unicode字符串传递给translate调用,则translate调用将异常,并且“正常”这似乎应该成为语言的一部分+谢谢你!(这样一个愚蠢的设计决定需要有一个同名的函数,它的操作方式不同。)另外,如果您不想手动定义标点字符:import string;translate_table={ord(unicode(c))for c in string.标点符号}注意:这不会翻译所有特殊的unicode标点符号(有吨…)您的
非字母或数字
缺少“$”和“&”。我建议使用
字符串。标点符号
而不是硬编码集合或字符。最好使用
导入字符串;字符串.标点符号
而不是实数编码中的硬编码而不是字母或数字。我明白了,你更愿意直言不讳。