unicode_escape
funktioniert im Allgemeinen nicht
Es stellt sich heraus, dass die Lösung string_escape
oder unicode_escape
im Allgemeinen nicht funktioniert - insbesondere nicht , wenn tatsächlich Unicode vorhanden ist.
Wenn Sie sicher sein können, dass jedes Nicht-ASCII-Zeichen maskiert wird (und denken Sie daran, dass alles, was über die ersten 128 Zeichen hinausgeht, kein ASCII-Zeichen ist), unicode_escape
wird dies das Richtige für Sie tun. Wenn Ihre Zeichenfolge jedoch bereits wörtliche Nicht-ASCII-Zeichen enthält, wird ein Fehler auftreten.
unicode_escape
ist grundsätzlich darauf ausgelegt, Bytes in Unicode-Text umzuwandeln. Aber an vielen Stellen - zum Beispiel im Python-Quellcode - sind die Quelldaten bereits Unicode-Text.
Dies kann nur dann richtig funktionieren, wenn Sie den Text zuerst in Bytes codieren. UTF-8 ist die sinnvolle Codierung für den gesamten Text, damit das funktioniert, oder?
Die folgenden Beispiele befinden sich in Python 3, sodass die Zeichenfolgenliterale sauberer sind. Das gleiche Problem besteht jedoch bei leicht unterschiedlichen Erscheinungsformen in Python 2 und 3.
>>> s = 'naïve \\t test'
>>> print(s.encode('utf-8').decode('unicode_escape'))
naïve test
Nun, das ist falsch.
Die neue empfohlene Methode zur Verwendung von Codecs, die Text in Text dekodieren, besteht darin, codecs.decode
direkt aufzurufen . Hilft das?
>>> import codecs
>>> print(codecs.decode(s, 'unicode_escape'))
naïve test
Überhaupt nicht. (Außerdem ist das Obige ein UnicodeError unter Python 2.)
Der unicode_escape
Codec geht trotz seines Namens davon aus, dass alle Nicht-ASCII-Bytes in der Latin-1-Codierung (ISO-8859-1) vorliegen. Sie müssten es also so machen:
>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve test
Aber das ist schrecklich. Dies beschränkt Sie auf die 256 Latin-1-Zeichen, als wäre Unicode überhaupt nicht erfunden worden!
>>> print('Ernő \\t Rubik'.encode('latin-1').decode('unicode_escape'))
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0151'
in position 3: ordinal not in range(256)
Hinzufügen eines regulären Ausdrucks zur Lösung des Problems
(Überraschenderweise haben wir jetzt keine zwei Probleme.)
Was wir tun müssen, ist, den unicode_escape
Decoder nur auf Dinge anzuwenden , von denen wir sicher sind, dass sie ASCII-Text sind. Insbesondere können wir sicherstellen, dass es nur auf gültige Python-Escape-Sequenzen angewendet wird, bei denen es sich garantiert um ASCII-Text handelt.
Der Plan ist, Escape-Sequenzen mit einem regulären Ausdruck zu finden und eine Funktion als Argument zu verwenden re.sub
, um sie durch ihren nicht entkoppelten Wert zu ersetzen.
import re
import codecs
ESCAPE_SEQUENCE_RE = re.compile(r'''
( \\U........ # 8-digit hex escapes
| \\u.... # 4-digit hex escapes
| \\x.. # 2-digit hex escapes
| \\[0-7]{1,3} # Octal escapes
| \\N\{[^}]+\} # Unicode characters by name
| \\[\\'"abfnrtv] # Single-character escapes
)''', re.UNICODE | re.VERBOSE)
def decode_escapes(s):
def decode_match(match):
return codecs.decode(match.group(0), 'unicode-escape')
return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
Und damit:
>>> print(decode_escapes('Ernő \\t Rubik'))
Ernő Rubik
'spam'+"eggs"+'''some'''+"""more"""
verarbeitet wird?