Làm cách nào để kiểm tra xem một chuỗi là unicode hoặc ascii?


271

Tôi phải làm gì trong Python để tìm ra chuỗi mã hóa nào?


56
Unicode không phải là mã hóa.
ulidtko

Quan trọng hơn, tại sao bạn nên quan tâm?
Johnsyweb

@Johnsyweb Bởi vì{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
alex

Câu trả lời:


295

Trong Python 3, tất cả các chuỗi là chuỗi các ký tự Unicode. Có một bytesloại chứa byte thô.

Trong Python 2, một chuỗi có thể là kiểu strhoặ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.


3
@ProsperousHeart: Có lẽ bạn đang sử dụng Python 3.
Greg Hewgill

124

Làm thế nào để biết nếu một đối tượng là một chuỗi unicode hoặc chuỗi byte

Bạn có thể sử dụng typehoặ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, strchỉ là một chuỗi byte. Python không biết mã hóa của nó là gì. Các unicodeloạ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, strgiống như Python 2 unicodevà được sử dụng để lưu trữ văn bản. Cái được gọi strtrong Python 2 được gọi bytestrong Python 3.


Làm thế nào để biết một chuỗi byte là hợp lệ utf-8 hoặc ascii

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)

Chỉ để tham khảo của người khác - str.decode không tồn tại trong python 3. Có vẻ như bạn phải unicode(s, "ascii")hoặc một cái gì đó
Shadow

3
Xin lỗi, ý tôi làstr(s, "ascii")
Shadow

1
Điều này không chính xác cho python 3
ProsperousHeart

2
@ProsperousHeart Đã cập nhật để bao trùm Python 3. Và để cố gắng giải thích sự khác biệt giữa chuỗi bytestrings và chuỗi unicode.
Mikel

44

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)

Điều này là sai. Trong Python 2.7 isinstance(u"x",basestring)trả về True.
PythonNut

11
@PythonNut: Tôi tin rằng đó là điểm chính. Việc sử dụng isinstance (x, basestring) đủ để thay thế các thử nghiệm kép khác biệt ở trên.
KQ.

5
Nó hữu ích trong nhiều trường hợp, nhưng rõ ràng không phải ý của người hỏi.
mhsmith

3
Đây là đáp án của câu hỏi. Tất cả những người khác đã hiểu sai những gì OP nói và đưa ra câu trả lời chung chung về việc kiểm tra kiểu trong Python.
fiatjaf

1
Không trả lời câu hỏi của OP. Tiêu đề của câu hỏi (một mình) COULD được diễn giải sao cho câu trả lời này là chính xác. Tuy nhiên, OP đặc biệt nói "tìm ra cái nào" trong mô tả của câu hỏi và câu trả lời này không giải quyết điều đó.
MD004

31

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.


Những slide đó có lẽ là phần giới thiệu tốt nhất về Unicode mà tôi đã gặp từ trước đến nay
Jonny

23

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ì byteskhông được xác định trong Python 2 và unicodekhô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.


6
Cách tốt hơn có lẽ là sử dụng six, và thử nghiệm six.binary_typesix.text_type
Ian Clelland

1
Bạn có thể sử dụng loại (s) .__ name__ để thăm dò tên loại.
Paulo Freitas

Tôi không chắc chắn về trường hợp sử dụng cho bit mã đó, trừ khi có lỗi logic. Tôi nghĩ rằng nên có một "không" trong mã python 2. Nếu không, bạn đang chuyển đổi mọi thứ thành chuỗi unicode cho Python 3 và ngược lại cho Python 2!
oligofren

Vâng, oligofren, đó là những gì nó làm. Các chuỗi bên trong tiêu chuẩn là Unicode trong Python 3 và ASCII trong Python 2. Vì vậy, các đoạn mã chuyển đổi văn bản thành loại chuỗi bên trong tiêu chuẩn (có thể là Unicode hoặc ASCII).
Dave Burton

12

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,

2
nó phải được if isinstance(obj, six.text_type) . Nhưng vâng, đây là câu trả lời đúng.
karantan

Không trả lời câu hỏi của OP. Tiêu đề của câu hỏi (một mình) COULD được diễn giải sao cho câu trả lời này là chính xác. Tuy nhiên, OP đặc biệt nói "tìm ra cái nào" trong mô tả của câu hỏi và câu trả lời này không giải quyết điều đó.
MD004

4

Lưu ý rằng trên Python 3, thật không công bằng khi nói bất kỳ:

  • strs là UTFx cho mọi x (ví dụ: UTF8)

  • strs là Unicode

  • strs được sắp xếp các bộ sưu tập các ký tự Unicode

strKiể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.


3

Đ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ủa tôi xứng đáng là phản ứng chính xác! Tôi đang sử dụng python 3 và tôi vẫn gặp vấn đề cho đến khi tìm thấy kho báu này!
mnsr

2

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 đó.


0

Để tương thích py2 / py3, chỉ cần sử dụng

import six if isinstance(obj, six.text_type)


0

Một cách tiếp cận đơn giản là kiểm tra xem có phải unicodelà 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 unicodemột có thể làm:

import builtins

i = 'cats'
if 'unicode' in dir(builtins):     # True in python 2, False in 3
  i = unicode(i)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.