Câu trả lời:
Trong Python 3, tất cả các chuỗi là chuỗi các ký tự Unicode. Có một bytes
loại chứa byte thô.
Trong Python 2, một chuỗi có thể là kiểu str
hoặc kiểu unicode
. Bạn có thể biết sử dụng mã nào đó như thế này:
def whatisthis(s):
if isinstance(s, str):
print "ordinary string"
elif isinstance(s, unicode):
print "unicode string"
else:
print "not a string"
Điều này không phân biệt "Unicode hoặc ASCII"; nó chỉ phân biệt các loại Python. Một chuỗi Unicode có thể bao gồm các ký tự thuần túy trong phạm vi ASCII và một chuỗi phụ có thể chứa ASCII, Unicode được mã hóa hoặc thậm chí là dữ liệu phi văn bản.
Bạn có thể sử dụng type
hoặc isinstance
.
Trong Python 2:
>>> type(u'abc') # Python 2 unicode string literal
<type 'unicode'>
>>> type('abc') # Python 2 byte string literal
<type 'str'>
Trong Python 2, str
chỉ là một chuỗi byte. Python không biết mã hóa của nó là gì. Các unicode
loại là cách an toàn hơn để lưu trữ văn bản. Nếu bạn muốn hiểu điều này nhiều hơn, tôi khuyên bạn nên http://farmdev.com/talks/unicode/ .
Trong Python 3:
>>> type('abc') # Python 3 unicode string literal
<class 'str'>
>>> type(b'abc') # Python 3 byte string literal
<class 'bytes'>
Trong Python 3, str
giống như Python 2 unicode
và được sử dụng để lưu trữ văn bản. Cái được gọi str
trong Python 2 được gọi bytes
trong Python 3.
Bạn có thể gọi decode
. Nếu nó tăng ngoại lệ UnicodeDecodeError, thì nó không hợp lệ.
>>> u_umlaut = b'\xc3\x9c' # UTF-8 representation of the letter 'Ü'
>>> u_umlaut.decode('utf-8')
u'\xdc'
>>> u_umlaut.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
unicode(s, "ascii")
hoặc một cái gì đó
str(s, "ascii")
Trong python 3.x, tất cả các chuỗi là chuỗi các ký tự Unicode. và thực hiện kiểm tra isinstance cho str (có nghĩa là chuỗi unicode theo mặc định) sẽ đủ.
isinstance(x, str)
Liên quan đến python 2.x, hầu hết mọi người dường như đang sử dụng một câu lệnh if có hai kiểm tra. Một cho str và một cho unicode.
Nếu bạn muốn kiểm tra xem bạn có tất cả một đối tượng 'giống như chuỗi' hay không, bạn có thể thực hiện như sau:
isinstance(x, basestring)
isinstance(u"x",basestring)
trả về True
.
Unicode không phải là mã hóa - để trích dẫn Kumar McMillan:
Nếu ASCII, UTF-8 và các chuỗi byte khác là "văn bản" ...
... thì Unicode là "văn bản";
nó là hình thức trừu tượng của văn bản
Hãy đọc Unicode của McMillan trong Python, Cuộc nói chuyện hoàn toàn được làm sáng tỏ từ PyCon 2008, nó giải thích mọi thứ tốt hơn nhiều so với hầu hết các câu trả lời liên quan trên Stack Overflow.
Nếu mã của bạn cần tương thích với cả Python 2 và Python 3, bạn không thể trực tiếp sử dụng những thứ như isinstance(s,bytes)
hoặc isinstance(s,unicode)
không gói chúng trong thử nghiệm / ngoại trừ hoặc thử nghiệm phiên bản python, vì bytes
không được xác định trong Python 2 và unicode
không được xác định trong Python 3 .
Có một số cách giải quyết xấu xí. Một điều cực kỳ xấu xí là so sánh tên của loại, thay vì so sánh chính loại đó. Đây là một ví dụ:
# convert bytes (python 3) or unicode (python 2) to str
if str(type(s)) == "<class 'bytes'>":
# only possible in Python 3
s = s.decode('ascii') # or s = str(s)[2:-1]
elif str(type(s)) == "<type 'unicode'>":
# only possible in Python 2
s = str(s)
Một cách giải quyết khác ít xấu xí hơn là kiểm tra số phiên bản Python, ví dụ:
if sys.version_info >= (3,0,0):
# for Python 3
if isinstance(s, bytes):
s = s.decode('ascii') # or s = str(s)[2:-1]
else:
# for Python 2
if isinstance(s, unicode):
s = str(s)
Cả hai đều là unpythonic, và hầu hết thời gian có lẽ là một cách tốt hơn.
six
, và thử nghiệm six.binary_type
vàsix.text_type
sử dụng:
import six
if isinstance(obj, six.text_type)
bên trong sáu thư viện, nó được biểu diễn dưới dạng:
if PY3:
string_types = str,
else:
string_types = basestring,
if isinstance(obj, six.text_type)
. Nhưng vâng, đây là câu trả lời đúng.
Lưu ý rằng trên Python 3, thật không công bằng khi nói bất kỳ:
str
s là UTFx cho mọi x (ví dụ: UTF8)
str
s là Unicode
str
s được sắp xếp các bộ sưu tập các ký tự Unicode
str
Kiểu của Python là (thông thường) một chuỗi các điểm mã Unicode, một số trong đó ánh xạ tới các ký tự.
Ngay cả trên Python 3, việc trả lời câu hỏi này không đơn giản như bạn tưởng tượng.
Một cách rõ ràng để kiểm tra các chuỗi tương thích ASCII là mã hóa đã thử:
"Hello there!".encode("ascii")
#>>> b'Hello there!'
"Hello there... ☃!".encode("ascii")
#>>> Traceback (most recent call last):
#>>> File "", line 4, in <module>
#>>> UnicodeEncodeError: 'ascii' codec can't encode character '\u2603' in position 15: ordinal not in range(128)
Các lỗi phân biệt các trường hợp.
Trong Python 3, thậm chí có một số chuỗi chứa các điểm mã Unicode không hợp lệ:
"Hello there!".encode("utf8")
#>>> b'Hello there!'
"\udcc3".encode("utf8")
#>>> Traceback (most recent call last):
#>>> File "", line 19, in <module>
#>>> UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 0: surrogates not allowed
Phương pháp tương tự để phân biệt chúng được sử dụng.
Điều này có thể giúp người khác, tôi bắt đầu thử nghiệm loại chuỗi của biến s, nhưng đối với ứng dụng của tôi, sẽ đơn giản hơn khi trả về s là utf-8. Quá trình gọi return_utf, sau đó biết nó đang xử lý vấn đề gì và có thể xử lý chuỗi một cách thích hợp. Mã này không còn nguyên sơ, nhưng tôi dự định nó sẽ là phiên bản bất khả tri của Python mà không cần kiểm tra phiên bản hoặc nhập sáu. Vui lòng bình luận với các cải tiến cho mã mẫu dưới đây để giúp đỡ người khác.
def return_utf(s):
if isinstance(s, str):
return s.encode('utf-8')
if isinstance(s, (int, float, complex)):
return str(s).encode('utf-8')
try:
return s.encode('utf-8')
except TypeError:
try:
return str(s).encode('utf-8')
except AttributeError:
return s
except AttributeError:
return s
return s # assume it was already utf-8
Bạn có thể sử dụng Trình phát hiện mã hóa toàn cầu , nhưng lưu ý rằng nó sẽ giúp bạn đoán đúng nhất, chứ không phải mã hóa thực tế, vì không thể biết mã hóa chuỗi "abc" chẳng hạn. Bạn sẽ cần lấy thông tin mã hóa ở nơi khác, ví dụ: giao thức HTTP sử dụng tiêu đề Kiểu nội dung cho điều đó.
Để tương thích py2 / py3, chỉ cần sử dụng
import six
if isinstance(obj, six.text_type)
Một cách tiếp cận đơn giản là kiểm tra xem có phải unicode
là hàm dựng sẵn không. Nếu vậy, bạn đang ở trong Python 2 và chuỗi của bạn sẽ là một chuỗi. Để đảm bảo mọi thứ trong unicode
một có thể làm:
import builtins
i = 'cats'
if 'unicode' in dir(builtins): # True in python 2, False in 3
i = unicode(i)