2010-01-28 30 views
9

Tôi có một chuỗi trong unicode và tôi cần trả lại N ký tự đầu tiên. Tôi đang thực hiện việc này:Trả về các ký tự đầu tiên của một chuỗi unicode

result = unistring[:5] 

nhưng tất nhiên là độ dài của chuỗi unicode! = Chiều dài ký tự. Bất kỳ ý tưởng nào? Giải pháp duy nhất là sử dụng lại?

Edit: Thông tin thêm

unistring = "Μεταλλικα" #Metallica written in Greek letters 
result = unistring[:1] 

returns->?

Tôi nghĩ rằng chuỗi unicode là hai byte (char), đó là lý do tại sao điều này xảy ra. Nếu tôi làm:

result = unistring[:2] 

tôi nhận được

M

đó là chính xác, Vì vậy, tôi phải luôn luôn cắt * 2 hay tôi nên chuyển đổi sang một cái gì đó?

+0

Bạn có chắc chắn rằng bạn có một chuỗi unicode thực tế không, và không (nói) xác định bằng dữ liệu UTF-8? Nếu vậy, làm thế nào để bạn xác định 'nhân vật'? (chuỗi unicode là chuỗi các codepoints (trong UCS-4 builds) hoặc codeunits.) –

+1

Từ máy chủ của chúng tôi: http://www.joelonsoftware.com/articles/Unicode.html – Will

+0

Xin vui lòng không. Điều đó không thực sự áp dụng ở đây. – Joey

Trả lời

6

Thật không may vì lý do lịch sử trước Python 3.0 có hai loại chuỗi. byte strings (str) and Unicode strings (unicode).

Trước khi hợp nhất trong Python 3.0 có hai cách để khai báo một chuỗi ký tự: unistring = "Μεταλλικα" là một chuỗi byte và unistring = u"Μεταλλικα" là một chuỗi unicode.

Lý do bạn thấy ? khi bạn làm result = unistring[:1] là do một số ký tự trong văn bản Unicode của bạn không thể được biểu diễn chính xác trong chuỗi không phải unicode. Bạn có thể đã thấy loại vấn đề này nếu bạn đã từng sử dụng một ứng dụng email thực sự cũ và nhận được email từ bạn bè ở các quốc gia như Hy Lạp chẳng hạn.

Vì vậy, trong Python 2.x nếu bạn cần xử lý Unicode, bạn phải làm điều đó một cách rõ ràng. Hãy xem phần giới thiệu này để xử lý Unicode bằng Python: Unicode HOWTO

+0

"Μεταλλικα" không phải là chuỗi ASCII. Nó là một chuỗi byte trong mã hóa được sử dụng để lưu tập lệnh. –

+2

Bạn đang đúng Đánh dấu nó là chính xác hơn để đề cập đến chúng như là chuỗi byte chứ không phải là chuỗi ASCII, tôi đã cập nhật câu trả lời cho phù hợp. Những gì tôi đã thực sự cố gắng để thể hiện là văn bản ASCII (hoặc chuỗi byte tương đương tùy thuộc vào các trang mã trên máy tính của bạn) là điều duy nhất có thể được xử lý một cách an toàn bằng các chuỗi byte. –

+1

Liên kết Unicode HOWTO đã chết – jeremyvillalobos

8

Khi bạn nói:

unistring = "Μεταλλικα" #Metallica written in Greek letters 

Bạn không có một chuỗi unicode. Bạn có một bytestring trong (có lẽ) UTF-8. Đó không phải là điều tương tự. Một chuỗi unicode là một kiểu dữ liệu riêng biệt trong Python. Bạn nhận được unicode bằng cách giải mã bytestrings bằng cách sử dụng mã hóa đúng:

unistring = "Μεταλλικα".decode('utf-8') 

hoặc bằng unicode chữ trong một file nguồn với việc kê khai mã hóa ngay

# coding: UTF-8 
unistring = u"Μεταλλικα" 

Chuỗi unicode sẽ làm những gì bạn muốn khi bạn làm unistring[:5].

+0

Bạn sẽ cần "#coding: utf-8" trước ví dụ .decode() và tệp phải được lưu thực sự trong utf-8. Python 2.x mặc định thành ASCII khi giải mã các tập lệnh. Bất kỳ việc sử dụng ký tự không phải ASCII nào cũng yêu cầu dòng #coding để khai báo mã hóa được sử dụng để lưu tệp. –

+1

Trong Python 2.5 và sau đó bạn cần khai báo mã hóa trên bất kỳ tệp nguồn nào có nội dung không phải ASCII, có. (Trước đó, nó chỉ là một cảnh báo.) Tuy nhiên, việc khai báo mã hóa sẽ không thay đổi ý nghĩa của mã, vì nó chỉ là các byte trong một dấu kiểm. –

+1

-1 Điều này không chính xác u "Một số kiểm tra Unicode" [: 5] Có thể cung cấp chuỗi bất hợp pháp, vì UTF-16 là mã hóa chiều rộng biến, do đó cắt chuỗi "Unicode" không chính xác như cắt chuỗi utf-8 – Artyom

4

Không có cách tiếp cận thẳng về phía trước với bất kỳ loại "chuỗi Unicode" nào.

Ngay cả chuỗi Python "Unicode" UTF-16 có các ký tự có độ dài thay đổi, vì vậy, bạn không thể chỉ cắt bằng cách sử dụng [: 5]. Bởi vì một số điểm mã Unicode có thể sử dụng nhiều hơn thì một "ký tự" tức là cặp thay thế.

Vì vậy, nếu bạn muốn cắt 5 điểm mã (lưu ý đây không phải là nhân vật ), do đó bạn có thể phân tích các văn bản, xem http://en.wikipedia.org/wiki/UTF-8http://en.wikipedia.org/wiki/UTF-16 định nghĩa. Vì vậy, bạn cần phải sử dụng một số mặt nạ bit để tìm ra ranh giới.

Ngoài ra bạn vẫn không nhận được ký tự. Bởi vì ví dụ. Từ "שָלוֹם" - hòa bình trong tiếng Do Thái "Shalom" bao gồm 4 ký tự và 6 ký tự mã "shin", nguyên âm "a" letter "lamed", chữ "vav" và nguyên âm "o" và chữ cái cuối cùng "mem".

Vì vậy, ký tự không phải là điểm mã.

Tương tự đối với hầu hết các ngôn ngữ phương Tây trong đó một chữ cái có dấu phụ có thể được biểu diễn dưới dạng hai điểm mã. Tìm kiếm ví dụ cho "unicode normalization".

Vì vậy ... Nếu bạn thực sự cần 5 ký tự đầu tiên, bạn phải sử dụng các công cụ như thư viện ICU. Ví dụ, có thư viện ICU cho Python cung cấp các ký tự biên lặp ranh giới.

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