2010-08-15 28 views
7

Vì vậy, tôi có trang này:Làm thế nào tôi có thể kiểm tra một chuỗi unicode Python để thấy rằng nó * thực sự * là Unicode đúng?

http://hub.iis.sinica.edu.tw/cytoHubba/

Rõ ràng đó là tất cả các loại điều sai lầm, vì nó được giải mã đúng nhưng khi tôi cố gắng để lưu nó trong postgres tôi nhận được:

DatabaseError: invalid byte sequence for encoding "UTF8": 0xedbdbf 

Các cơ sở dữ liệu clams lên sau đó và từ chối làm bất cứ điều gì mà không có một rollback, mà sẽ là một chút khó khăn để phát hành (câu chuyện dài). Có cách nào để tôi kiểm tra xem điều này có xảy ra trước khi nó truy cập cơ sở dữ liệu không? source.encode ("utf-8") hoạt động mà không có sự cố, vì vậy tôi không chắc chắn những gì đang xảy ra ...

+0

Bạn có chắc chắn rằng kết nối của bạn được đặt để sử dụng UTF-8 không? – Wolph

+0

Đúng, 300.000 trang web khác đã được thêm vào chỉ là tốt, nó chỉ là một trong những thất bại ... –

Trả lời

9

Có một lỗi trong trăn 2.x chỉ là trăn cố định 3.x. Trong thực tế, lỗi này là ngay cả trong biểu tượng OS X (nhưng không phải là một glibc).

Đây là những gì đang diễn ra:

Python 2.x không nhận ra cặp UTF8 thay thế [1] như là không hợp lệ (đó là những gì chuỗi nhân vật của bạn là)

này nên được tất cả những gì cần thiết:

foo.decode('utf8').encode('utf8') 

Nhưng nhờ đó lỗi họ không sửa chữa, nó không bắt cặp thay thế.

Hãy thử điều này trong python 2.x và sau đó trong 3.x:

b'\xed\xbd\xbf'.decode('utf8') 

Nó sẽ ném ra một lỗi (chính xác) trong sau này. Họ cũng không sửa nó trong nhánh 2.x. Xem [2] và [3] để biết thêm

[1] http://tools.ietf.org/html/rfc3629#section-4

[2] http://bugs.python.org/issue9133

[3] http://bugs.python.org/issue8271#msg102209

+0

Cảm ơn bạn, đây là những gì tôi nghi ngờ. Được chọn là chính xác. –

+0

Không sao cả. Tôi đã cố gắng làm nhiều hơn hoặc ít hơn những gì bạn đang làm để lọc dữ liệu của tôi khi thực hiện COPY thành postgres. Những gì tôi đã làm chỉ là để cho nó thất bại và lọc ra các hàng riêng lẻ dựa trên các đầu ra lỗi. Nó được dựa trên ý tưởng chung về cách mã sao chép trong pgloader hoạt động http://pgfoundry.org/projects/pgloader/ – mikelikespie

+0

không liên quan: nếu bạn muốn sửa các cặp thay thế: 'u '[\ ud83d \ ude42]'. mã hóa ('utf-16', 'thay thế') giải mã ('utf-16') = u '[\ U0001f642]' ' – jfs

1

Một đối tượng Python unicode là một chuỗi các điểm mã Unicode và theo định nghĩa unicode thích hợp. Một chuỗi python str là một chuỗi các byte có thể là các ký tự Unicode được mã hóa với một mã hóa nhất định (UTF-8, Latin-1, Big5, ...).

Câu hỏi đầu tiên là nếu source là đối tượng unicode hoặc chuỗi str. Điều đó có nghĩa là source.encode("utf-8") chỉ hoạt động có nghĩa là bạn có thể chuyển đổi source thành chuỗi được mã hóa UTF-8, nhưng bạn đang thực hiện nó trước khi chuyển nó đến hàm cơ sở dữ liệu? Cơ sở dữ liệu dường như mong đợi các đầu vào của nó được mã hóa bằng UTF-8 và phàn nàn rằng tương đương với source.decode("utf-8") không thành công.

Nếu source là một đối tượng unicode, nó phải được mã hóa sang UTF-8 trước khi bạn vượt qua nó vào cơ sở dữ liệu:

source = u'abc' 
call_db(source.encode('utf-8')) 

Nếu source là một str mã hóa như một cái gì đó khác hơn là UTF-8, bạn nên giải mã mã hóa đó và sau đó mã hóa đối tượng Unicode kết quả thành UTF-8:

source = 'abc' 
call_db(source.decode('Big5').encode('utf-8')) 
+1

Xin lỗi, tôi cần phải làm rõ. nguồn là một đối tượng unicode được mã hóa tốt trong Python, mọi thứ bị phá vỡ khi tôi cố gắng gửi nó đến postgres ... –

0

Chính xác bạn đang làm gì? Nội dung không thực sự giải mã tốt như utf-8:

>>> import urllib 
>>> webcontent = urllib.urlopen("http://hub.iis.sinica.edu.tw/cytoHubba/").read() 
>>> unicodecontent = webcontent.decode("utf-8") 
>>> type(webcontent) 
<type 'str'> 
>>> type(unicodecontent) 
<type 'unicode'> 
>>> type(unicodecontent.encode("utf-8")) 
<type 'str'> 

Hãy chắc chắn rằng bạn hiểu sự khác biệt giữa các chuỗi Unicode và utf-8 chuỗi mã hóa, mặc dù. Những gì bạn cần gửi đến cơ sở dữ liệu là unicodecontent.encode("utf-8") (tương tự như webcontent, nhưng bạn đã giải mã để xác minh rằng bạn không có chuỗi byte không hợp lệ trong nguồn của bạn).

Tôi thực sự là WoLpH nói kiểm tra cài đặt trên cơ sở dữ liệu và kết nối cơ sở dữ liệu.

+0

Tôi đang sử dụng Django, mã hóa mọi thứ đúng cách, nhưng postgres quyết định mã hóa (hoặc chuỗi được mã hóa) là xấu, vì lý do nào đó ... Mọi thứ tôi làm trong Python đều hoạt động, đó là lý do tại sao tôi không thể phát hiện ra nó. Có lẽ đó là một lỗi postgres? –

0

Cuối cùng, tôi chọn chỉ làm việc xung quanh điều này, bắt lỗi và khôi phục giao dịch bằng cách sử dụng quản lý giao dịch của Django. Tôi bị băn khoăn về lý do tại sao nó sẽ xảy ra, mặc dù ...

0

Để giải quyết vấn đề tương tự của tôi với django/postgress bây giờ làm điều gì đó như thế này

class SafeTextField(models.TextField) 
    def get_prep_value(self, value): 
     encoded = base64.encodestring(value).strip() 
     return super(SafeTextField, self).get_prep_value(encoded) 
    def to_python(self, value): 
     decoded = base64.decodestring(value) 
     return super(SafeTextField, self).to_python(decoded) 
Các vấn đề liên quan