webentwicklung-frage-antwort-db.com.de

Wie bekomme ich str.translate mit Unicode-Strings zusammen?

Ich habe folgenden Code:

import string
def translate_non_alphanumerics(to_translate, translate_to='_'):
    not_letters_or_digits = u'!"#%\'()*+,-./:;<=>[email protected][\]^_`{|}~'
    translate_table = string.maketrans(not_letters_or_digits,
                                       translate_to
                                         *len(not_letters_or_digits))
    return to_translate.translate(translate_table)

Was sich hervorragend für Nicht-Unicode-Strings eignet:

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

Scheitert jedoch bei Unicode-Strings:

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

Ich kann den Absatz über "Unicode-Objekte" in der Dokumentation Python 2.6.2 docs der Methode str.translate () nicht verstehen.

Wie mache ich das für Unicode-Strings?

56
Daryl Spitzer

Die Unicode-Version von translate erfordert eine Zuordnung von Unicode-Ordinalen (die Sie für ein einzelnes Zeichen mit ord abrufen können) zu Unicode-Ordinalen. Wenn Sie Zeichen löschen möchten, ordnen Sie None zu.

Ich habe Ihre Funktion dahingehend geändert, dass ein Diktat erstellt wird, das die Ordinalzahl jedes Zeichens mit der Ordinalzahl von dem, was Sie übersetzen möchten, darstellt.

def translate_non_alphanumerics(to_translate, translate_to=u'_'):
    not_letters_or_digits = u'!"#%\'()*+,-./:;<=>[email protected][\]^_`{|}~'
    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: Es stellt sich heraus, dass die Übersetzungszuordnung von der Unicode-Ordinalzahl (über ord) entweder einer anderen Unicode-Ordinalzahl, einer Unicode-Zeichenfolge oder None (zum Löschen) zugeordnet werden muss. Ich habe daher den Standardwert für translate_to in ein Unicode-Literal geändert. Zum Beispiel:

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

In dieser Version können Sie die Buchstaben relativ zueinander machen 

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

Ich habe mir die folgende Kombination aus meiner ursprünglichen Funktion und der Version von Mike ausgedacht, die mit Unicode und ASCII - Strings funktioniert:

def translate_non_alphanumerics(to_translate, translate_to=u'_'):
    not_letters_or_digits = u'!"#%\'()*+,-./:;<=>[email protected][\]^_`{|}~'
    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: "Erzwungen" translate_to zum Unicode für den Unicode translate_table. Danke, Mike.

5
Daryl Spitzer

Für einen einfachen Hack, der sowohl für str- als auch für Unicode-Objekte funktioniert, konvertiert Die Übersetzungstabelle vor dem Ausführen von translate () in Unicode:

import string
def translate_non_alphanumerics(to_translate, translate_to='_'):
    not_letters_or_digits = u'!"#%\'()*+,-./:;<=>[email protected][\]^_`{|}~'
    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)

Der Haken dabei ist, dass es alle str-Objekte implizit in Unicode konvertiert.... Fehler, wenn to_translate Nicht-ASCII-Zeichen enthält.

4
eswald

Anstatt alle Zeichen, die ersetzt werden müssen, angeben zu müssen, können Sie sie auch in umgekehrter Richtung anzeigen und stattdessen nur die gültigen Zeichen angeben:

import re

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

    return result

Dies funktioniert sowohl mit Unicode als auch mit regulären Zeichenfolgen und behält den Typ bei (wenn sowohl replacement_character als auch source offensichtlich vom selben Typ sind).

0

Ich habe herausgefunden, dass Sie in Python 2.7 mit dem Typ str schreiben würden

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

mit dem Typ unicode würden Sie sagen

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

In Python 3.6 würden Sie schreiben

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

vielleicht ist das hilfreich.

0
davidav