Chuyển đến nội dung chính

Cách chuyển Bytes thành String trong Python

Để chuyển bytes thành chuỗi trong Python, chúng ta có thể dùng phương thức .decode(), chỉ định bảng mã phù hợp.
· 8 phút đọc

Khám phá cùng AI

Một trong những kiểu chuỗi dựng sẵn ít được biết đến trong Python là bytes, một dãy bất biến (immutable) các số nguyên. Mỗi số nguyên biểu diễn một byte dữ liệu. Dữ liệu thường được truyền qua mạng và giữa các chương trình ở dạng bytes. Bytes không thể đọc trực tiếp bằng mắt người, nên chúng ta thường cần chuyển chúng thành chuỗi trong các chương trình Python.

Hướng dẫn này khám phá các kỹ thuật chuyển bytes thành chuỗi trong Python. Nếu bạn quan tâm đến thao tác ngược lại, hãy xem hướng dẫn của tôi về cách chuyển chuỗi thành bytes trong Python.

Hãy bắt đầu với câu trả lời ngắn gọn cho những bạn cần nhanh.

Câu trả lời ngắn: Cách chuyển Bytes thành String trong Python

Công cụ chính để chuyển bytes thành chuỗi trong Python là phương thức .decode():

data = b"\xc3\xa9clair"
text = data.decode(encoding="utf-8")
print(text)
éclair

Phương thức .decode() trả về một chuỗi biểu diễn đối tượng bytes. Trong ví dụ này, sử dụng giải mã UTF-8. UTF-8 là bảng mã mặc định, nên không bắt buộc trong ví dụ trên, nhưng chúng ta cũng có thể dùng các bảng mã khác.

Tìm hiểu về Bytes và Strings trong Python

Python có cấu trúc dữ liệu dựng sẵn bytes, là một dãy bất biến các số nguyên trong khoảng từ 0 đến 255. Một số nguyên trong khoảng 256 giá trị này có thể được biểu diễn bằng tám bit dữ liệu, tức một byte. Do đó, mỗi phần tử trong một đối tượng bytes là một số nguyên đại diện cho một byte.

Hãy dùng hàm tạo bytes() để tạo một đối tượng bytes từ một danh sách:

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
print(type(data))
<class 'bytes'>

Dãy số nguyên này là bất biến:

data[0] = 100
Traceback (most recent call last):
 ...
   data[0] = 100
   ~~~~^^^
TypeError: 'bytes' object does not support item assignment

Python sẽ phát sinh TypeError khi chúng ta cố thay đổi một giá trị trong dãy này. Hãy xác nhận rằng một đối tượng bytes chỉ có thể chứa các số nguyên từ 0 đến 255:

data = bytes([254, 255, 256])
Traceback (most recent call last):
 ...
   data = bytes([254, 255, 256])
          ^^^^^^^^^^^^^^^^^^^^^^
ValueError: bytes must be in range(0, 256)

ValueError cho biết một số nguyên biểu diễn byte phải là phần tử của range(0, 256). Điểm cuối của range bị loại trừ, đúng theo quy ước về dãy số trong Python.

Chúng ta có thể hiển thị đối tượng bytes bằng print():

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
print(data)
b'DataCamp'

Biểu diễn này cho thấy đối tượng bytes được thể hiện bằng các ký tự. Python hiển thị các số nguyên bằng những ký tự ASCII tương ứng với các giá trị đó. Tiền tố b trước các ký tự trong dấu nháy cho biết đây là một đối tượng bytes.

Chúng ta cũng có thể tạo một đối tượng bytes bằng literal bytes trực tiếp:

data = b"DataCamp"
print(data)
print(data[0])
b'DataCamp'
68

Đối tượng được hiển thị bằng ký tự, nhưng các phần tử của nó là số nguyên.

Tuy nhiên, các đối tượng bytes chỉ có thể đọc được bằng mắt người khi dùng các số nguyên tương ứng với ký tự ASCII có thể in. Vì ASCII là bảng mã 7-bit, nó có 128 mã, nhưng chỉ 95 ký tự ASCII là có thể in.

Các số nguyên từ 0 đến 127 không có ký tự ASCII có thể in và các số nguyên từ 128 đến 255 sẽ được hiển thị dưới dạng số thập lục phân:

data = bytes([0, 68, 97, 116, 97, 67, 97, 109, 112, 200])
print(data)
b'\x00DataCamp\xc8'

Phần tử đầu tiên trong danh sách giờ là 0, không phải ký tự có thể in trong ASCII. Đối tượng bytes hiển thị số nguyên này là \x00, dạng thập lục phân của 0. Số nguyên cuối cùng là 200, nằm ngoài phạm vi ASCII nhưng vẫn trong phạm vi số nguyên có thể dùng trong bytes. Python hiển thị số nguyên này là \xc8, tức 200 ở hệ thập lục phân.

Cấu trúc dữ liệu bytes và chuỗi có những điểm chung. Cả hai đều là các dãy bất biến, nhưng bytes chứa số nguyên, còn chuỗi chứa ký tự:

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
print(data[0])

​text = "DataCamp"
print(text[0])
68
D

Bytes được dùng để truyền dữ liệu qua mạng và giữa các giao diện khác nhau. Phần tiếp theo của bài viết sẽ khám phá cách chuyển bytes thành chuỗi.

Chuyển Bytes thành Chuỗi: Phương thức .decode()

Một đối tượng bytes trong Python chỉ có thể đọc được bằng mắt người khi nó chứa các ký tự ASCII đọc được. Trong hầu hết ứng dụng, các ký tự này là không đủ. Chúng ta có thể chuyển một đối tượng bytes thành chuỗi bằng phương thức .decode():

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
text = data.decode()

print(text)
print(type(text))
DataCamp
<class 'str'>

Tuy nhiên, có nhiều bảng mã khác nhau để chuyển đổi giữa bytes và chuỗi. Các số nguyên trong ví dụ trên biểu diễn các ký tự ASCII có thể in. Tuy nhiên, bảng mã mặc định được dùng khi không truyền đối số cho .decode() là UTF-8 chứ không phải ASCII. UTF-8 là bảng mã được dùng rộng rãi nhất cho các ký tự Unicode.

128 mã UTF-8 đầu tiên trùng với mã ASCII, đó là lý do đối tượng bytes trên được giải mã thành chuỗi "DataCamp" trong ví dụ.

Tuy nhiên, Unicode chứa gần 150.000 ký tự. UTF-8 mã hóa tất cả các ký tự không phải ASCII trong Unicode bằng hai byte trở lên.

Hãy tạo một đối tượng bytes mới và giải mã nó:

data = bytes([195, 169])
print(data)

text = data.decode()
print(text)
b'\xc3\xa9'
é

Đối tượng bytes chứa hai byte: các số nguyên 195 và 169. Python hiển thị dạng thập lục phân của các byte này. Tuy nhiên, .decode() trả về một chuỗi bằng cách giải mã đối tượng bytes theo bảng mã UTF-8. Cặp byte b'\xc3\xa9' biểu diễn chữ e có dấu sắc, é.

Phương thức .decode() nhận một đối số tùy chọn để chỉ định bảng mã:

text = data.decode("utf-8")
print(text)
é

UTF-8 là bảng mã mặc định, nhưng có thể dùng các bảng mã khác. Chúng ta cũng có thể chuyển một chuỗi thành đối tượng bytes bằng phương thức chuỗi .encode() với nhiều bảng mã khác nhau:

text = "éclair"
data = text.encode("utf-8")
print(data)

data = text.encode("utf-16")
print(data)
b'\xc3\xa9clair'
b'\xff\xfe\xe9\x00c\x00l\x00a\x00i\x00r\x00'

Cùng một chuỗi có thể được chuyển thành các đối tượng bytes khác nhau tùy theo bảng mã chúng ta dùng.

Lỗi mã hóa

Việc lựa chọn bảng mã có thể dẫn đến lỗi nếu dùng bảng mã khác nhau khi chuyển đổi giữa bytes và chuỗi. Hãy dùng ví dụ với chuỗi "éclair" được mã hóa sang bytes bằng UTF-8:

text = "éclair"
data = text.encode("utf-8")
print(data)
b'\xc3\xa9clair'

Dãy byte này biểu diễn các ký tự theo bảng mã UTF-8. Phương thức .decode() sẽ phát sinh lỗi nếu chúng ta dùng sai bảng mã:

text = data.decode("ascii")
print(text)
Traceback (most recent call last):
 ...
   text = data.decode("ascii")
          ^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

Tuy nhiên, chúng ta có thể truyền đối số tùy chọn errors để xử lý lỗi. Giá trị mặc định của tham số errors là "strict", sẽ phát sinh lỗi khi gặp ký tự không hợp lệ.

Phương thức .decode() có thể được gọi với errors="ignore" để bỏ qua tất cả ký tự không hợp lệ:

text = data.decode("ascii", errors="ignore")
print(text)
clair

Ký tự đầu tiên trong chuỗi gốc là é, không phải ký tự ASCII. Do đó, .decode() trả về một chuỗi thiếu ký tự đầu tiên.

Một lựa chọn khác là gọi .decode() với errors="replace", thay thế các byte không hợp lệ bằng �:

text = data.decode("ascii", errors="replace")
print(text)
��clair

Kết quả này cho thấy các ký tự bị thiếu trong chuỗi. Cách xử lý lỗi phụ thuộc vào ứng dụng.

Chuyển Bytes thành Chuỗi bằng str()

Phương thức .decode() là con đường chính để chuyển bytes thành chuỗi. Tuy nhiên, cũng có thể dùng trực tiếp hàm tạo str(). Dùng str() trên một đối tượng bytes sẽ tạo chuỗi biểu diễn các byte thô:

data = b'\xc3\xa9clair'
text = str(data)

print(text)
print(type(text))
b'\xc3\xa9clair'
<class 'str'>

Tuy nhiên, hàm tạo str() cũng nhận đối số encoding, cho phép chúng ta tạo chuỗi dựa trên một bảng mã cụ thể:

text = str(data, encoding='utf-8')
print(text)
éclair

Chuyển Bytes thành Chuỗi với codecs.decode()

Mô-đun codecs trong thư viện chuẩn của Python cung cấp giao diện để mã hóa và giải mã dữ liệu. Mô-đun này cũng cung cấp hàm .decode() có thể dùng để chuyển bytes của Python thành chuỗi:

import codecs

​data = b'\xc3\xa9clair'
text = codecs.decode(data, encoding='utf-8')
print(text)
éclair

Các kỹ thuật chuyển đổi thay thế này không phải là phương thức của kiểu bytes mà là các hàm yêu cầu truyền đối tượng bytes làm đối số.

Kết luận

Dữ liệu thường được truyền ở dạng bytes, và nhiều ứng dụng Python cần chuyển đổi giữa bytes và chuỗi. Một đối tượng bytes là dãy bất biến các byte, có thể chuyển thành string bằng một trong nhiều bảng mã ký tự.

Con đường chính để chuyển bytes của Python thành chuỗi là phương thức .decode(), cho phép người dùng chọn bảng mã và chiến lược xử lý lỗi.

Bạn có thể tiếp tục học Python với các hướng dẫn và khóa học sau:

Stephen Gruppetta

Tác giả

Stephen Gruppetta

Tôi học Vật lý và Toán ở bậc đại học tại Đại học Malta. Sau đó, tôi chuyển đến London và lấy bằng Tiến sĩ Vật lý tại Imperial College. Tôi nghiên cứu các kỹ thuật quang học mới để chụp ảnh võng mạc người. Hiện nay, tôi tập trung vào việc viết về Python, truyền đạt về Python và giảng dạy Python.

Chủ đề

Liên quan