web-dev-qa-db-ja.com

Unicode文字列で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))
    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

Str.translate()メソッドの Python 2.6.2 docs の「Unicodeオブジェクト」の段落を理解することはできません。

Unicode文字列に対してこれを機能させるにはどうすればよいですか?

56
Daryl Spitzer

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

edit:翻訳マッピングは、Unicode序数から(ordを介して)別のUnicode序数、Unicode文字列、またはNone(削除する)。したがって、translate_toのデフォルト値をUnicodeリテラルに変更しました。例えば:

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

このバージョンでは、比較的相手に手紙を送ることができます

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

元の関数と、UnicodeとASCII文字列で動作する Mike のバージョン)の次の組み合わせを思いつきました。

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: "強制" translate_toユニコードのユニコードtranslate_table。マイクありがとう。

5
Daryl Spitzer

StrオブジェクトとUnicodeオブジェクトの両方で機能する単純なハックの場合、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
eswald

置換する必要があるすべての文字を指定する代わりに、逆の方法で表示し、代わりに次のように有効な文字のみを指定することもできます。

import re

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

    return result

これは、Unicodeと通常の文字列で機能し、タイプを保持します(両方のreplacement_charactersourceは同じタイプです。

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

多分これは役に立ちます。

0
davidav