Heim >Backend-Entwicklung >Python-Tutorial >Erfahren Sie mehr über Python-Codierung und Unicode

Erfahren Sie mehr über Python-Codierung und Unicode

巴扎黑
巴扎黑Original
2017-04-30 14:50:051407Durchsuche

Ich bin mir sicher, dass es viele Erklärungen zu Unicode und Python gibt, aber um mein Verständnis und meine Verwendung zu erleichtern, habe ich noch vor, noch ein paar Dinge darüber zu schreiben.

Bytestream vs. Unicode-Objekt

Definieren wir zunächst einen String in Python. Wenn Sie den String-Typ verwenden, speichern Sie tatsächlich einen Byte-String.

[  a ][  b ][  c ] = "abc"
[ 97 ][ 98 ][ 99 ] = "abc"

In diesem Beispiel ist die Zeichenfolge abc eine Bytezeichenfolge. 97., 98 und 99 sind ASCII-Codes. Die Definition in Python 2.x besteht darin, alle Zeichenfolgen als ASCII zu behandeln. Leider ist ASCII der am wenigsten verbreitete Standard unter den lateinischen Zeichensätzen.

ASCII verwendet die ersten 127 Zahlen für die Zeichenzuordnung. Zeichenzuordnungen wie Windows-1252 und UTF-8 haben die gleichen ersten 127 Zeichen. Es ist sicher, String-Kodierungen zu mischen, wenn der Wert jedes Bytes in Ihrem String kleiner als 127 ist. Allerdings birgt diese Annahme eine Gefahr, wie weiter unten erläutert wird.

Es treten Probleme auf, wenn Ihre Zeichenfolge Bytes mit einem Wert größer als 126 enthält. Schauen wir uns eine in Windows-1252 codierte Zeichenfolge an. Die Zeichenzuordnung in Windows-1252 ist eine 8-Bit-Zeichenzuordnung, sodass insgesamt 256 Zeichen vorhanden sind. Die ersten 127 sind die gleichen wie ASCII und die nächsten 127 sind andere durch Windows-1252 definierte Zeichen.

A windows-1252 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 150 ] = "abc–"

Windows-1252 ist immer noch eine Bytefolge, aber haben Sie gesehen, dass der Wert des letzten Bytes größer als 126 ist? Wenn Python versucht, diesen Bytestrom mit dem Standard-ASCII-Standard zu dekodieren, wird ein Fehler gemeldet. Mal sehen, was passiert, wenn Python diese Zeichenfolge dekodiert:

>>> x = "abc" + chr(150)
>>> print repr(x)
'abc\x96'
>>> u"Hello" + x
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeDecodeError: &#39;ASCII&#39; codec can&#39;t decode byte 0x96 in position 3: ordinal not in range(128)

​ Verwenden wir UTF-8, um eine weitere Zeichenfolge zu kodieren:

A UTF-8 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"
[0x61] [0x62] [0x63] [0xe2]  [ 0x80] [ 0x93] = "abc-"

Wenn Sie die Ihnen vertraute Unicode-Codierungstabelle zur Hand nehmen, werden Sie feststellen, dass der dem englischen Bindestrich entsprechende Unicode-Codepunkt 8211 (0×2013) ist. Dieser Wert ist größer als der ASCII-Maximalwert von 127. Es kann ein Wert gespeichert werden, der größer als ein Byte ist. Da 8211 (0×2013) aus zwei Bytes besteht, muss UTF-8 einige Tricks anwenden, um dem System mitzuteilen, dass zum Speichern eines Zeichens drei Bytes erforderlich sind. Schauen wir uns an, wann Python das Standard-ASCII verwenden wird, um eine UTF-8-codierte Zeichenfolge mit einem Zeichenwert größer als 126 zu codieren.

>>> x = "abc\xe2\x80\x93"
>>> print repr(x)
&#39;abc\xe2\x80\x93&#39;
>>> u"Hello" + x
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeDecodeError: &#39;ASCII&#39; codec can&#39;t decode byte 0xe2 in position 3: ordinal not in range(128)

Wie Sie sehen, verwendet Python standardmäßig immer die ASCII-Kodierung. Wenn das vierte Zeichen verarbeitet wird, gibt Python einen Fehler aus, da sein Wert 226 ist, was größer als 126 ist. Dies ist das Problem bei der gemischten Kodierung.

Byte-Stream dekodieren

Beim ersten Erlernen von Python Unicode kann der Begriff „Dekodierung“ verwirrend sein. Sie können einen Bytestream in ein Unicode-Objekt dekodieren und ein Unicode-Objekt in einen Bytestream kodieren.

Python muss wissen, wie man einen Bytestream in ein Unicode-Objekt dekodiert. Wenn Sie einen Byte-Stream erhalten, rufen Sie dessen Methode „decode“ auf, um daraus ein Unicode-Objekt zu erstellen

Sie sollten den Bytestream so früh wie möglich in Unicode dekodieren.

>>> x = "abc\xe2\x80\x93"
>>> x = x.decode("utf-8")
>>> print type(x)
<type &#39;unicode&#39;>
>>> y = "abc" + chr(150)
>>> y = y.decode("windows-1252")
>>> print type(y)
>>> print x + y
abc–abc–

​Unicode in einen Byte-Stream kodieren

Ein Unicode-Objekt ist eine kodierungsunabhängige Darstellung eines Textes. Sie können ein Unicode-Objekt nicht einfach ausgeben. Es muss vor der Ausgabe in einen Byte-String umgewandelt werden. Python wäre für diese Art von Arbeit gut geeignet, obwohl Python beim Codieren von Unicode in einen Byte-Stream standardmäßig ASCII verwendet. Dieses Standardverhalten kann große Probleme verursachen.

>>> u = u"abc\u2013"
>>> print u
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: &#39;ascii&#39; codec can&#39;t encode character u&#39;\u2013&#39; in position 3: ordinal not in range(128)
>>> print u.encode("utf-8")
abc–

​Codecs-Modul

verwenden Das Codecs-Modul kann bei der Verarbeitung von Byteströmen eine große Hilfe sein. Sie können Dateien mit der definierten Kodierung öffnen und der Inhalt, den Sie aus der Datei lesen, wird automatisch in Unicode-Objekte konvertiert.

​Versuchen Sie Folgendes:

>>> import codecs
>>> fh = codecs.open("/tmp/utf-8.txt", "w", "utf-8")
>>> fh.write(u"\u2013")
>>> fh.close()

Es ruft ein Unicode-Objekt ab und schreibt es in der UTF-8-Kodierung in die Datei. Sie können es auch in anderen Situationen verwenden.

​Versuchen Sie Folgendes:

Beim Lesen von Daten aus einer Datei erstellt codecs.open ein Dateiobjekt, das die UTF-8-codierte Datei automatisch in ein Unicode-Objekt konvertieren kann.

Lassen Sie uns das obige Beispiel fortsetzen, dieses Mal mit URL-Streams.

>>> stream = urllib.urlopen("http://www.google.com")
>>> Reader = codecs.getreader("utf-8")
>>> fh = Reader(stream)
>>> type(fh.read(1))
<type &#39;unicode&#39;>
>>> Reader
<class encodings.utf_8.StreamReader at 0xa6f890>

Einzeilige Version:

>>> fh = codecs.getreader("utf-8")(urllib.urlopen("http://www.google.com"))
>>> type(fh.read(1))

Bei Codec-Modulen muss man sehr vorsichtig sein. Was Sie übergeben, muss ein Unicode-Objekt sein, andernfalls wird der Bytestrom automatisch als ASCII dekodiert.

>>> x = "abc\xe2\x80\x93" # our "abc-" utf-8 string
>>> fh = codecs.open("/tmp/foo.txt", "w", "utf-8")
>>> fh.write(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.5/codecs.py", line 638, in write
  return self.writer.write(data)
File "/usr/lib/python2.5/codecs.py", line 303, in write
  data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe2 in position 3: ordinal not in range(128)

Ups, Python hat wieder angefangen, ASCII zu verwenden, um alles zu dekodieren.

​Das Problem der Aufteilung des UTF-8-Byte-Streams

Da es sich bei einer UTF-8-codierten Zeichenfolge um eine Liste von Bytes handelt, funktionieren len()- und Slicing-Vorgänge nicht ordnungsgemäß. Verwenden Sie zunächst die Zeichenfolge, die wir zuvor verwendet haben.

[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"

Gehen Sie als Nächstes wie folgt vor:

>>> my_utf8 = "abc–"
>>> print len(my_utf8)
6

Was für ein Pferd? Es sieht aus wie 4 Zeichen, aber das Ergebnis von len besagt, dass es 6 sind. Denn len zählt die Anzahl der Bytes und nicht die Anzahl der Zeichen.

>>> print repr(my_utf8)
&#39;abc\xe2\x80\x93&#39;

Teilen wir nun diese Zeichenfolge auf.

>>> my_utf8[-1] # Get the last char
&#39;\x93&#39;

Lassen Sie mich gehen, das Segmentierungsergebnis ist das letzte Byte, nicht das letzte Zeichen.

Um UTF-8 korrekt zu segmentieren, sollten Sie den Bytestream besser dekodieren, um ein Unicode-Objekt zu erstellen. Dann können Sie sicher operieren und zählen.

>>> my_unicode = my_utf8.decode("utf-8")
>>> print repr(my_unicode)
u&#39;abc\u2013&#39;
>>> print len(my_unicode)
4
>>> print my_unicode[-1]
–

Wenn Python

automatisch kodiert/dekodiert In einigen Fällen werden Fehler ausgegeben, wenn Python automatisch mit ASCII kodiert/dekodiert.

  第一个案例是当它试着将Unicode和字节串合并在一起的时候。

>>> u"" + u"\u2019".encode("utf-8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe2 in position 0:   ordinal not in range(128)

  在合并列表的时候会发生同样的情况。Python在列表里有string和Unicode对象的时候会自动地将字节串解码为Unicode。

>>> ",".join([u"This string\u2019s unicode", u"This string\u2019s utf-8".encode("utf-8")])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe2 in position 11:  ordinal not in range(128)

  或者当试着格式化一个字节串的时候:

>>> "%s\n%s" % (u"This string\u2019s unicode", u"This string\u2019s  utf-8".encode("utf-8"),)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe2 in position 11: ordinal not in range(128)

  基本上当你把Unicode和字节串混在一起用的时候,就会导致出错。

  在这个例子里面,你创建一个utf-8文件,然后往里面添加一些Unicode对象的文本。就会报UnicodeDecodeError错误。

>>> buffer = []
>>> fh = open("utf-8-sample.txt")
>>> buffer.append(fh.read())
>>> fh.close()
>>> buffer.append(u"This string\u2019s unicode")
>>> print repr(buffer)
[&#39;This file\xe2\x80\x99s got utf-8 in it\n&#39;, u&#39;This string\u2019s unicode&#39;]
>>> print "\n".join(buffer)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe2 in position 9: ordinal not in range(128)

  你可以使用codecs模块把文件作为Unicode加载来解决这个问题。

>>> import codecs
>>> buffer = []
>>> fh = open("utf-8-sample.txt", "r", "utf-8")
>>> buffer.append(fh.read())
>>> fh.close()
>>> print repr(buffer)
[u&#39;This file\u2019s got utf-8 in it\n&#39;, u&#39;This string\u2019s unicode&#39;]
>>> buffer.append(u"This string\u2019s unicode")
>>> print "\n".join(buffer)
This file’s got utf-8 in it

This string’s unicode

  正如你看到的,由codecs.open 创建的流在当数据被读取的时候自动地将比特串转化为Unicode。

  最佳实践

  1.最先解码,最后编码

  2.默认使用utf-8编码

  3.使用codecs和Unicode对象来简化处理

  最先解码意味着无论何时有字节流输入,需要尽早将输入解码为Unicode。这会防止出现len( )和切分utf-8字节流发生问题。

  最后编码意味着只有在准备输入的时候才进行编码。这个输出可能是一个文件,一个数据库,一个socket等等。只有在处理完成之后才编码unicode对象。最后编码也意味着,不要让Python为你编码Unicode对象。Python将会使用ASCII编码,你的程序会崩溃。

  默认使用UTF-8编码意味着:因为UTF-8可以处理任何Unicode字符,所以你最好用它来替代windows-1252和ASCII。

  codecs模块能够让我们在处理诸如文件或socket这样的流的时候能少踩一些坑。如果没有codecs提供的这个工具,你就必须将文件内容读取为字节流,然后将这个字节流解码为Unicode对象。

  codecs模块能够让你快速的将字节流转化为Unicode对象,省去很多麻烦。

  解释UTF-8

  最后的部分是让你能入门UTF-8,如果你是个超级极客可以无视这一段。

  利用UTF-8,任何在127和255之间的字节是特别的。这些字节告诉系统这些字节是多字节序列的一部分。

Our UTF-8 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"

  最后3字节是一个UTF-8多字节序列。如果你把这三个字节里的第一个转化为2进制可以看到以下的结果:

11100010

  前3比特告诉系统它开始了一个3字节序列226,128,147。

  那么完整的字节序列。

11100010 10000000 10010011

  然后你运用三字节序列的下面的掩码。

1110xxxx 10xxxxxx 10xxxxxx
XXXX0010 XX000000 XX010011 Remove the X&#39;s
0010       000000   010011 Collapse the numbers
00100000 00010011          Get Unicode number 0x2013, 8211 The "–"

  这是基本的UTF-8入门,如果想知道更多的细节,可以去看UTF-8的维基页面。

  原文链接: ERIC MORITZ   翻译: 伯乐在线 - 贱圣OMG

Das obige ist der detaillierte Inhalt vonErfahren Sie mehr über Python-Codierung und Unicode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Threads in Python verstehenNächster Artikel:Threads in Python verstehen