2012-03-08 28 views
7

Tôi đã thử nghiệm một lúc với Python 2.X và unicode. Nhưng tôi đã đạt đến một điểm mà nó không có ý nghĩa.Python 2.X: Tại sao tôi không thể xử lý Unicode đúng cách?

Vấn đề đầu tiên:

Một số mã sẽ giải thích rõ ràng những gì tôi có ý nghĩa. Biến txt ở đây để mô phỏng hàm dịch pyqt4. Trả về một QString.

# -*- coding: utf-8 -*- 
from PyQt4 import QtCore 
txt = QtCore.QString(u'può essere/sarà/日本語') 
txtUnicode1 = unicode(txt, errors='replace') 
txtUnicode2 = unicode(txt) 

Khi in() - ing hai chuỗi unicode, tôi nhận được:

pu essere/sar/???

PUO essere/Sara/日本語

Chắc chắn tôi có thể nhận được điều tương tự bằng cách sử dụng QString .__ str __(), nhưng quan điểm của tôi là sự hiểu biết, vì vậy vì lợi ích của các đối số tôi muốn biết:

  • Tại sao các lỗi = 'thay thế' thay thế tất cả các ký tự được mã hóa khi nó chỉ được thực hiện trong trường hợp có lỗi?
  • Có vấn đề gì khi chỉ sử dụng unicode (QString) để đặt mã vạch QString thành chuỗi unicode phù hợp để hiển thị?

vấn đề thứ hai:

Tôi cố gắng để hiểu mã hóa/giải mã.

>>> a = u'può essere/sarà/日本' 
>>> b = a.encode('utf-8') 
>>> a 
u'pu\xf2 essere/sar\xe0/\u65e5\u672c' 
>>> b 
'pu\xc3\xb2 essere/sar\xc3\xa0/\xe6\x97\xa5\xe6\x9c\xac' 
>>> print a 
può essere/sarà/日本 
>>> print b 
può essere/sarà/日本 
  • Liệu in giải mã a và b?
  • UTF-8 được mã hóa được mã hóa là được giải mã hoàn toàn? Tôi có nên in chuỗi được mã hóa không?
  • Sự khác biệt giữa chuỗi unicode được mã hóa và giải mã là gì?
+0

Bạn có thể chỉ làm rõ nếu bạn đang sử dụng python 2.x hoặc 3.x. Trong khi nó (hiện tại) hiển nhiên dựa trên tiền tố chuỗi u, nó là thông tin quan trọng cho câu hỏi này, và trong tương lai tiền tố u sẽ được thêm trở lại python3 (pep414) – ironchefpython

+0

Chắc chắn, Python 2.x (tôi chỉnh sửa) – Aki

+0

Tôi đã thấy một buổi diễn tập cho [talk] này (http://lanyrd.com/2012/pycon/spccy/http://lanyrd.com/2012/pycon/spccy/) gần đây. Bạn nên xem video/slide của nó một khi pycon được thực hiện. – Daenyth

Trả lời

5

Hãy kích hoạt chế độ chờ cũ, IDLE và xem liệu chúng tôi có thể sao chép những gì bạn đang xem hay không.

IDLE 1.1.4  
>>> a = u'può essere/sarà/日本' 

Unsupported characters in input 
>>> a = u'pu\xf2 essere/sar\xe0/\u65e5\u672c' 
>>> b = a.encode('utf-8') 
>>> a 
u'pu\xf2 essere/sar\xe0/\u65e5\u672c' 
>>> b 
'pu\xc3\xb2 essere/sar\xc3\xa0/\xe6\x97\xa5\xe6\x9c\xac' 
>>> print a 
può essere/sarà/日本 
>>> print b 
può essere/sarà/日本 

Lưu ý rằng tôi thấy điều gì đó khác khi tôi in b. Điều này là do vỏ của tôi (IDLE) không giải thích một chuỗi các byte như văn bản UTF-8, mà là sử dụng mã hóa ký tự nền tảng của tôi, cp1252.

Hãy kiểm tra kỹ điều này.

>>> import sys 
>>> sys.stdout.encoding 
'cp1252' 

Yup, đó là lý do tại sao tôi có hành vi khác với bạn. Bởi vì sys.stdout.encoding của bạn là UTF-8. Và đó là lý do tại sao, mặc dù ab là các giá trị hoàn toàn khác nhau, chúng hiển thị như nhau; thiết bị đầu cuối của bạn diễn giải byte là UTF-8.

Vì vậy, bạn có thể tự hỏi nếu chúng ta có thể chuyển đổi chuỗi của chúng ta về các ký tự unicode a vào một chuỗi các byte có thể được hiển thị trong IDLE

>>> c = a.encode('cp1252') 

Traceback (most recent call last): 
    File "<pyshell#19>", line 1, in -toplevel- 
    c = a.encode('cp1252') #uses default encoding 
    File "C:\Python24\lib\encodings\cp1252.py", line 18, in encode 
    return codecs.charmap_encode(input,errors,encoding_map) 
UnicodeEncodeError: 'charmap' codec can't encode characters in position 20-21: character maps to <undefined> 

Câu trả lời là không có; cp1252 không hỗ trợ mã hóa ký tự Trung Quốc dưới dạng byte.

+0

Vì vậy, bạn có thể in một bản in vì python phát hiện đó là chuỗi UTF-8 và chuyển đổi nó thành cp1252? Trong khi nó chỉ dịch b là một chuỗi mã hóa cp1252? – Aki

+0

Không, tôi có thể in 'a' vì' a' là một chuỗi ký tự unicode (16 bit). Nhưng 'b' là một chuỗi các byte *, và do đó python cần phải chuyển đổi nó thành ký tự, và do đó sử dụng mã hóa mặc định nền tảng, cp1252 – ironchefpython

+0

Phiên bản IDLE của tôi sử dụng UTF-8. Thật không may, tôi không thể lặp lại bài kiểm tra vì nó áp dụng một số loại mã hóa cho * đầu vào *. –

5

Trước hết, tôi khuyên bạn nên đọc bài viết tuyệt vời của Joel Spolesky, The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets. Nó không phải về Python, nhưng sẽ giúp bạn hiểu những gì đang diễn ra.

Sự khác biệt giữa chuỗi unicode và chuỗi bình thường trở nên rõ ràng hơn trong Python 3, nhưng điều này đúng trong Python 2. Chuỗi unicode chứa biểu diễn unicode của chuỗi, chuỗi bình thường là chuỗi byte chứa mã hóa đại diện unicode. Tài liệu cho số unicode giải thích những gì đang xảy ra. Bằng cách chuyển thông số errorsunicode hoạt động khác khi thông số không được chuyển và đang cố gắng giải mã chuỗi. Nó không rõ ràng mã hóa nó đang cố gắng để giải mã từ, nhưng nó có thể nghĩ rằng nó utf-8 khi nó thực sự utf-16, hoặc tương tự.

Tuyên bố print mã hóa chuỗi unicode thành bất kỳ mã hóa nào mà thiết bị đầu cuối của bạn đang sử dụng. Điều này có thể ascii, hoặc nó có thể là utf-8 hoặc cái gì khác.print a thực sự đang thực hiện print a.encode('utf-8') phía sau hậu trường.

Tôi chưa trả lời tất cả câu hỏi của bạn, nhưng bài viết tôi liên kết sẽ trả lời hầu hết trong số họ. Hi vọng điêu nay co ich!

Các vấn đề liên quan