14. Chuỗi, byte và Unicode

Dữ liệu văn bản và nhị phân là các họ đối tượng riêng biệt trong Python.strđại diện cho văn bản Unicode.bytesđại diện cho dữ liệu nhị phân bất biến.bytearrayđại diện cho dữ liệu nhị phân có thể thay đổi.

Sự tách biệt này là một trong những lựa chọn thiết kế thời gian chạy quan trọng nhất của Python 3. Văn bản có các ký tự và mã hóa. Dữ liệu nhị phân có byte. CPython triển khai các khái niệm này với các bố cục đối tượng, API và bất biến khác nhau.

14.1 Văn bản và Dữ liệu nhị phân

Một chuỗi là văn bản:python id="ly45du" s = "hello" Đối tượng byte là dữ liệu nhị phân:python id="1wh8hi" b = b"hello" Chúng có thể trông giống nhau đối với nội dung ASCII nhưng chúng thuộc các loại khác nhau.python id="iqtxra" print(type("hello")) # <class 'str'> print(type(b"hello")) # <class 'bytes'> Python không ngầm trộn lẫn chúng:python id="8bzmko" "hello" + b"world" # TypeError Đây là cố ý. Việc kết hợp văn bản và byte yêu cầu quyết định mã hóa.```python id="8w5t7o" text = "hello" data = text.encode("utf-8")

again = data.decode("utf-8")


## 14.2`str`Đại diện cho văn bản Unicode

mt con trăn`str`là mt chui các đim mã Unicode.```python id="tq2xfz"
s = "Python 🐍"
print(len(s))

len(s)đếm điểm mã, không mã hóa byte.```python id="lxgm2u" s = "é"

print(len(s)) # 1 print(len(s.encode("utf-8"))) # 2


S khác bit này xut hin xuyên sut ni b CPython:```text id="c3cd4w"
str
    logical Unicode text

bytes
    encoded or arbitrary binary data
```## 14.3 Điểm mã Unicode

Đim mã Unicode là mt giá tr nguyên được gán theo tiêu chun Unicode.

Ví d:

| Nhân vt | Đim mã |
| --------- | ---------- |
|`A`       | `U+0041`   |
| `é`       | `U+00E9`   |
| ``       | `U+4E2D`   |
| `🐍`      | `U+1F40D`|

Python phơi bày điu này thông qua`ord`Và`chr`.

```python id="cvt38d"
print(ord("A"))        # 65
print(hex(ord("🐍")))  # 0x1f40d

print(chr(0x1f40d))    # 🐍
```Mt chui không được lưu tr dưới dng byte UTF-8 bên trong theo nghĩa ph quát đơn gin. CPython chn b cc bên trong được ti ưu hóa cho ni dung ca chui.

## 14.4 Biểu diễn chuỗi linh hoạt

CPython s dng cách biu din ni b linh hot cho chui Unicode.

Ý tưởng chính rt đơn gin:```text id="hj5qoo"
Use the smallest fixed-width storage that can represent every code point in the string.
```V mt khái nim:

| Đim mã ti đa trong chui |         Chiu rng lưu tr |
| ---------------------------- | --------------------: |
| ch ASCII |  1 byte mi ký t |
| Lên đến`U+00FF`|  1 byte mi ký t |
| Lên đến`U+FFFF`| 2 byte mi ký t |
| Bên trên`U+FFFF`| 4 byte mi ký t |

Ví d:```python id="k8wqod"
"abc"       # compact ASCII path
"café"      # may fit in 1-byte storage
"中"        # needs 2-byte storage
"🐍"        # needs 4-byte storage
```Thiết kế này tránh lãng phí bn byte cho mi ký t đối vi văn bn nng ASCII thông thường trong khi vn h tr tt c các đim mã Unicode.

## 14.5 Siêu dữ liệu đối tượng chuỗi

Chui CPython không ch lưu tr d liu ký t.

Các lĩnh vc khái nim bao gm:```text id="xr6949"
object header
length
hash cache
state flags
kind
compact flag
ASCII flag
ready flag
character data
optional UTF-8 cache
```B cc C chính xác là dành riêng cho tng phiên bn, nhưng các bt biến quan trng hơn tên trường.

Siêu d liu quan trng:

| Siêu d liu | Mc đích |
| ------------ | --------------------------------------------- |
| Chiu dài | S đim mã Unicode |
| B nh đệm băm | Lưu tr hàm băm sau ln tính toán đầu tiên |
| Loi | Chiu rng lưu tr |
| C ASCII | Đường dn nhanh cho chui ASCII |
| C nh gn | Liu d liu có được lưu tr gn tiêu đề đối tượng hay không |
| B đệm UTF-8 | Biu mu được mã hóa trong b nh đệm để s dng API C |

Chui không th thay đổi nên siêu d liu được lưu trong b nh đệm s an toàn. Sau khi tính toán, hàm băm vn hp l.

## 14.6 Tính bất biến của chuỗi

Chui Python là bt biến.```python id="8lnw2h"
s = "hello"
s[0] = "H"       # TypeError
```Các thao tác to chui mi:```python id="q4ux6e"
s = "hello"
t = "H" + s[1:]

print(s)    # hello
print(t)    # Hello
```Tính bt biến mang li cho CPython mt s li thế:```text id="ylorrg"
hash values can be cached
strings can be safely interned
strings can be shared across dictionaries
strings can be used as dict keys
substring operations cannot mutate originals
```Cái giá phi tr là vic ni chui lp đi lp li có th phân b nhiu chui trung gian nếu được viết kém.

## 14.7 Băm chuỗi

Chui có th băm được.```python id="7pmw4s"
hash("name")
```Hàm băm ca chui được tính t ni dung ca nó. Vì các chui là bt biến nên CPython có th lưu tr kết qu bên trong đối tượng chui.

Điu này quan trng vì các chui được s dng nhiu làm khóa t đin:```text id="n69066"
module globals
object attribute names
class dictionaries
keyword argument names
JSON-like data
configuration maps
protocol field names
```Nếu không có hàm băm chui được lưu trong b nh đệm, vic tra cu thuc tính và tra cu t đin s tn kém hơn.

## 14.8 Thực tập chuỗi

Thc tp có nghĩa là s dng li mt đối tượng chui cho các giá tr chui bng nhau trong các trường hp đã chn.```python id="alsrhm"
a = "identifier"
b = "identifier"

print(a is b)   # may be True
```CPython thc hin nhiu chui ging như mã định danh vì chúng ph biến trong tra cu thuc tính và không gian tên.

Thc tp rt hu ích cho:```text id="te68vu"
attribute names
variable names
keyword names
module names
common internal strings
```Vi các chui ni b, kim tra đẳng thc thường có th tr thành kim tra con tr sau kim tra hàm băm trong các đường dn bên trong.

Nhưng mã người dùng không nên ph thuc vào nhn dng chui tùy ý.

Chính xác:```python id="k4ah3b"
if a == b:
    ...
```Không đúng:```python id="tgxz95"
if a is b:
    ...
```S dng`is`ch dành cho ng nghĩa nhn dng, đặc bit là các tài liu đơn l như`None`.

## 14.9 Mã hóa

Mã hóa chuyn đổi văn bn thành byte.```python id="n587av"
s = "café"
b = s.encode("utf-8")

print(b)        # b'caf\xc3\xa9'
```Chui là văn bn Unicode. UTF-8 là mt biu din byte bên ngoài.

Các mã hóa ph biến:

| Mã hóa | S dng |
| -------- | ----------------------------------- |
| UTF-8 | Web, tp, API, h thng Unix |
| UTF-16 | Mt s API nn tng và định dng tp |
| UTF-32 | B nh Unicode có chiu rng c định |
| Tiếng Latinh-1 | Ánh x byte phương Tây kế tha |
| ASCII | Tp hp con tiếng Anh 7-bit |

CPython không coi mã hóa là thuc tính ca`str`. Mt chui được gii mã văn bn. Mã hóa được s dng khi vượt qua ranh gii byte.

Gii mã ## 14.10

Gii mã chuyn đổi byte thành văn bn.```python id="n1sd4m"
b = b"caf\xc3\xa9"
s = b.decode("utf-8")

print(s)        # café
```Nếu các byte không hp l đối vi mã hóa đã chn thì vic gii mã s không thành công tr khi s dng trình x lý li.```python id="83jkr9"
b = b"\xff"

b.decode("utf-8")                 # UnicodeDecodeError
b.decode("utf-8", errors="ignore")
b.decode("utf-8", errors="replace")
```Trình x lý li bao gm:```text id="j4u46t"
strict
ignore
replace
backslashreplace
surrogateescape
surrogatepass
```Li mã hóa là mt phn ca ranh gii văn bn, không phi các thao tác chui thông thường.

## 14.11 Ranh giới UTF-8

Hu hết văn bn bên ngoài hin đại là UTF-8.

Ví d:```text id="ps2rks"
source files
JSON
HTTP payloads
HTML
Markdown
logs
configuration files
database text protocols
```Mt quy tc thc tế:```text id="cszoaq"
inside Python
    use str

at file, network, process, and binary protocol boundaries
    encode or decode explicitly
```Ví d:```python id="le5dmj"
from pathlib import Path

text = Path("notes.txt").read_text(encoding="utf-8")
data = text.encode("utf-8")
```Điu này gi cho ranh gii rõ ràng.

## 14.12 Mã hóa mã nguồn

Các tp ngun Python được gii mã trước khi phân tích cú pháp.

Mã hóa ngun mc định là UTF-8 tr khi khai báo mã hóa có quy định khác.

Ví d:```python id="cndzxu"
# -*- coding: utf-8 -*-

name = "café"
```Trình mã thông báo hot động trên văn bn ngun được gii mã. Chui ký t sau đó tr thành Python`str`các đối tượng tr khi chúng là byte bng ch.```python id="wu9nv8"
s = "abc"       # str
b = b"abc"      # bytes
```S khác bit này được thc hin trong quá trình phân tích cú pháp và biên dch.

## 14.13 Chuỗi ký tự

Python có mt s dng chui ký t.```python id="9uk2iv"
"hello"
'hello'
"""hello"""
'''hello'''
r"\n"
f"value = {x}"
```Tin t ch nh hưởng đến vic phân tích cú pháp:

| Tin t | Ý nghĩa |
| ------------ | ------------------------------- |
|`r`| Chui ký t thô |
|`f`| Chui ký t được định dng |
|`b`| Byte theo nghĩa đen |
|`u`| Tin t tương thích lch s |
| kết hp |`fr`, `rf`, `br`, `rb`|

Mt chui thô thay đổi cách trình phân tích cú pháp gii thích các ký t thoát.```python id="5il9aw"
s = r"\n"
print(s)        # \n
```Nó vn to bình thường`str`.

## Đối tượng 14,14 byte`bytes`đại diện cho dữ liệu nhị phân bất biến.```python id="rdc547"
b = b"hello"
```Đối tượng byte là mt chui các s nguyên trong phm vi t 0 đến 255.```python id="a55532"
b = b"ABC"

print(b[0])     # 65
print(b[1])     # 66
```Ct lát tr v mt đối tượng byte khác:```python id="ry5nl7"
print(b[1:])    # b'BC'
```Bi vì`bytes`là bt biến, nó có th băm được.```python id="524c01"
d = {b"key": "value"}
```Byte rt hu ích cho:```text id="ujfy6z"
network protocols
binary files
cryptographic data
compressed data
encoded text
database wire formats
image and audio formats
```## Bố cục đối tượng 14,15 byte

Đối tượng byte có kích thước thay đổi.

V mt khái nim:```text id="kr49t3"
PyBytesObject
    PyVarObject header
        ob_size = number of bytes
    hash cache
    byte data
    trailing NUL byte for C compatibility
```Byte NUL  cui giúp ích khi truyn d liu ti các API C có chui C, nhưng byte có th cha byte NUL được nhúng:```python id="z96jr9"
b = b"a\0b"
print(len(b))   # 3
```Vì vy, byte không được coi là chui kết thúc bng NUL thông thường tr khi API đặc bit cho phép điu đó và ni dung được xác định là an toàn.

## 14.16 Đối tượng Bytearray`bytearray`là dữ liệu nhị phân có thể thay đổi.```python id="cltuuo"
buf = bytearray(b"hello")
buf[0] = ord("H")

print(buf)      # bytearray(b'Hello')
```Mt bytearray h tr sa đổi ti ch:```python id="vf2c2m"
buf.append(33)
buf.extend(b" world")
```Nó không th băm được vì ni dung ca nó có th thay đổi.```python id="2mamf7"
hash(bytearray(b"abc"))     # TypeError
```V mt khái nim, bytearray gn ging vi danh sách byte có th thay đổi hơn, nhưng được trin khai dưới dng b đệm byte nh gn hơn là mt mng tham chiếu đối tượng s nguyên Python.

## 14,17 Byte so với Danh sách Int

So sánh:```python id="mm43w3"
b = b"abc"
xs = [97, 98, 99]
```Đối tượng bytes lưu tr byte thô mt cách gn gàng.

Danh sách lưu tr các tham chiếu đến các đối tượng s nguyên Python.

V mt khái nim:```text id="6zghb9"
bytes
    [97][98][99]

list
    [ptr][ptr][ptr]
      |    |    |
      v    v    v
     int  int  int
```Đối vi d liu nh phân,`bytes`Và`bytearray`b nh hiu qu hơn nhiu.

## 14.18 Chế độ xem bộ nhớ`memoryview`hiển thị bộ đệm của đối tượng khác.```python id="lk88r7"
buf = bytearray(b"hello")
view = memoryview(buf)

view[0] = ord("H")

print(buf)      # bytearray(b'Hello')
```Chế độ xem b nh tránh sao chép.

Nó rt hu ích khi ct hoc truyn d liu nh phân gia các API:```python id="fmmfbg"
data = bytearray(b"abcdef")
view = memoryview(data)[2:5]

print(view.tobytes())     # b'cde'
```Chế độ xem gi cho nhà xut khu tn ti và thc thi các quy tc trn đời ca b đệm.

## 14.19 Giao thức bộ đệm

Giao thc đệm là giao thc cp C đằng sau`memoryview`.

Nó cho phép các đối tượng hin th b nh thô cho các đối tượng khác.

Các nhà xut khu đệm ph biến:```text id="yt656l"
bytes
bytearray
array.array
memoryview
mmap
third-party arrays such as NumPy arrays
custom extension objects
```Giao thc mô t:```text id="va15hu"
pointer to memory
length
item size
format
number of dimensions
shape
strides
readonly flag
lifetime callbacks
```Điu này làm cho vic x lý nh phân không sao chép có th thc hin được.

## 14.20 I/O văn bản và I/O nhị phân

Tp tin có th được m  chế độ văn bn hoc chế độ nh phân.

Chế độ văn bn gii mã byte thành chui:```python id="ztfr4f"
with open("notes.txt", "r", encoding="utf-8") as f:
    text = f.read()
```Chế độ nh phân tr v byte:```python id="2vcxb8"
with open("notes.txt", "rb") as f:
    data = f.read()
```Chế độ văn bn x lý mã hóa, gii mã và dch dòng mi.

Chế độ nh phân cung cp byte thô.

Chn da trên mô hình d liu:```text id="ifzmcj"
human-readable text
    text mode, str

protocol bytes or exact file bytes
    binary mode, bytes
```## 14.21 Lỗi ranh giới phổ biến

Mt li ph biến là trn văn bn và byte  ranh gii.

Không đúng:```python id="zctul0"
def send(sock, message):
    sock.sendall(message)       # fails if message is str
```Chính xác:```python id="daxwma"
def send(sock, message):
    data = message.encode("utf-8")
    sock.sendall(data)
```Để nhn:```python id="jynmly"
data = sock.recv(4096)
text = data.decode("utf-8")
```Gi chuyn đổi rõ ràng để mã hóa hin th.

## 14.22 Nối chuỗi

Chui là bt biến nên vic ni chui s to ra mt chui mi.```python id="fnu5rd"
s = "a"
s = s + "b"
s = s + "c"
```Điu này có th phân b nhiu ln.

Đối vi nhiu phn, thích`join`:

```python id="xnzlkg"
parts = ["a", "b", "c"]
s = "".join(parts)
```Để truyn phát văn bn, hãy s dng`io.StringIO`:

```python id="1icewe"
from io import StringIO

buf = StringIO()
buf.write("a")
buf.write("b")
buf.write("c")

s = buf.getvalue()
```CPython có các ti ưu hóa cho mt s trường hp ni cc b, nhưng mã không nên ph thuc vào chúng để có hiu sut chung.

## Tòa nhà 14,23 byte

Byte cũng không thay đổi được.

Vic ni các byte lp đi lp li có cùng mt vn đề v phân b.```python id="bufv11"
data = b""
for chunk in chunks:
    data += chunk
```Tt hơn:```python id="5ojx6g"
data = b"".join(chunks)
```Đối vi xây dng gia tăng có th thay đổi:```python id="bpfowr"
buf = bytearray()
for chunk in chunks:
    buf.extend(chunk)

data = bytes(buf)
```Đối vi vic xây dng nh phân ging như tp tin:```python id="s6mtb3"
from io import BytesIO

buf = BytesIO()
buf.write(b"abc")
buf.write(b"def")

data = buf.getvalue()
```## 14.24 Chuẩn hóa Unicode

Các chui Unicode khác nhau có th trông ging nhau.

Ví d:```python id="d3pxs7"
a = "é"          # single code point U+00E9
b = "e\u0301"    # e plus combining acute accent

print(a == b)    # False
```Chúng có th hin th tương t nhau, nhưng chúng là các chui đim mã khác nhau.

Bình thường hóa khi so sánh văn bn ca con người:```python id="7m77tv"
import unicodedata

a = unicodedata.normalize("NFC", a)
b = unicodedata.normalize("NFC", b)

print(a == b)    # True
```Các hình thc chun hóa ph biến:

| Mu | Ý nghĩa |
| ---- | ----------------------------- |
| NFC | Thành phn kinh đin |
| NFD | Phân hy kinh đin |
| NFKC | Thành phn tương thích |
| NFKD | Phân hy kh năng tương thích |

Chun hóa là mi quan tâm  cp độ Unicode, không phi là mi quan tâm v b cc đối tượng CPython. Nhưng nó quan trng để x lý văn bn chính xác.

## 14.25 Trường hợp gấp

So sánh không phân bit ch hoa ch thường nên s dng`casefold`, không`lower`.

```python id="xo53gl"
a = "Straße"
b = "strasse"

print(a.lower() == b.lower())       # often False
print(a.casefold() == b.casefold()) # True

casefoldđược thiết kế để kết hợp không phân biệt chữ hoa chữ thường.

Đối với mã định danh, tên tệp, tên người dùng và trường giao thức, hãy xác định quy tắc chuẩn hóa và viết hoa chính xác. Đừng đoán.

14.26 Cụm đồ thị

Một ký tự mà người dùng nhìn thấy có thể chứa nhiều điểm mã.

Ví dụ:```python id="g55aom" s = "👨‍👩‍👧‍👦" print(len(s))


Python`str`lp ch mc các đim mã, không phi cm biu đồ.```python id="1i0lb4"
s[0]
```có th ch tr v mt phn ca ký t hin th.

Để chnh sa văn bn giao din người dùng, di chuyn con tr, ct ngn và chiu rng hin th, vic lp ch mc đim mã có th không đủ. Bn cn phân đon đồ th nhn biết Unicode.

## 14.27 Chiến lược lỗi mã hóa

Mã hóa có th tht bi nếu mt ký t không th được biu din.```python id="j37zya"
"é".encode("ascii")       # UnicodeEncodeError
```Chiến lược li kim soát hành vi:```python id="9s35v1"
"é".encode("ascii", errors="ignore")
"é".encode("ascii", errors="replace")
"é".encode("ascii", errors="backslashreplace")
```Đối vi ranh gii tp và quy trình, hãy chn cách x lý li có ch ý.

Mt chiến lược hướng ti Unix ph biến là`surrogateescape`, cho phép các byte không th gii mã được thc hin chuyến đi kh hi`str`không mt d liu trong mt s bi cnh h thng tp tin và môi trường.

## 14.28 Mã hóa hệ thống tập tin

Đường dn tp vượt qua ranh gii văn bn và byte.

Python thường hin th các đường dn dưới dng`str`, nhưng h điu hành thường hot động trên các chui byte được mã hóa hoc các định dng chui gc ca nn tng.

CPython có logic mã hóa h thng tp để chuyn đổi gia các chui Python và biu din đường dn nn tng.

Quy tc thc tế:```text id="pqbj4c"
use pathlib and str paths for normal application code
use bytes paths only when you need exact low-level byte behavior
```Ví d:```python id="w0jnqu"
from pathlib import Path

p = Path("data") / "notes.txt"
text = p.read_text(encoding="utf-8")
```## 14.29 Chế độ xem API C của Unicode

Mã m rng C thường cn chp nhn hoc to chui.

Các hot động ph biến bao gm:```text id="psub45"
create Unicode from UTF-8
convert Unicode to UTF-8
inspect length
read code points
parse arguments as str
```Ví d v khái nim:```c id="ffcssi"
PyObject *s = PyUnicode_FromString("hello");
```Và:```c id="umgbtx"
const char *p = PyUnicode_AsUTF8(obj);
```Con tr UTF-8 được mt s API tr v có th tr vào b đệm do đối tượng chui s hu. Tui th ca nó ph thuc vào đối tượng s hu còn sng.

Mã m rng không được gii phóng con tr đó.

## 14.30 Chế độ xem byte của API C

Byte hin th b nh nh phân lin k.

Ví d v khái nim:```c id="g34cn9"
PyObject *b = PyBytes_FromStringAndSize(data, len);
```Truy cp:```c id="q3e1ai"
char *p = PyBytes_AS_STRING(b);
Py_ssize_t n = PyBytes_GET_SIZE(b);
```Các macro nhanh gi s đối tượng thc s là mt đối tượng byte.

API được kim tra an toàn hơn nên được s dng  các ranh gii công cng.

Byte có th cha byte NUL, vì vy hãy luôn s dng độ dài rõ ràng.

## 14.31 Chọn đúng loại

| Cn | Loi |
| ------------------------- | ----------------------------- |
| Văn bn con người |`str`|
| Văn bn được mã hóa |`bytes`|
| D liu giao thc nh phân |`bytes`|
| B đệm nh phân có th thay đổi |`bytearray`|
| Chế độ xem không sao chép |`memoryview`|
| Nhiu đon văn bn |`list[str]`cng thêm`"".join`|
| Nhiu đon nh phân |`list[bytes]`cng thêm`b"".join`|
| Người viết văn bn gia tăng |`io.StringIO`|
| Nhà văn nh phân gia tăng |`io.BytesIO`hoc`bytearray`|

Loi s phn ánh mô hình d liu. Tránh s dng`str`cho các byte tùy ý. Tránh s dng`bytes`cho văn bn được gii mã.

## 14.32 Mô hình tinh thần

S dng mô hình này:```text id="dluupp"
str
    immutable Unicode code point sequence
    optimized internal storage
    cached hash
    explicit encode/decode boundary

bytes
    immutable byte sequence
    compact binary storage
    hashable
    no text semantics unless decoded

bytearray
    mutable byte sequence
    compact binary storage
    useful for incremental construction

memoryview
    zero-copy view over buffer-exporting object
    lifetime tied to exporter
```Li x lý văn bn thường đến t các đim mã, byte, mã hóa, cm biu đồ, chun hóa và độ rng hin th khó hiu. Mô hình đối tượng ca CPython gi văn bn và byte riêng bit để các quyết định này vn rõ ràng.

## 14.33 Tóm tắt`str`là đối tượng văn bản Unicode của CPython. Nó không thể thay đổi, có thể băm và được tối ưu hóa nội bộ thông qua bộ nhớ linh hoạt, hàm băm được lưu trong bộ nhớ đệm và thực tập. Nó đại diện cho văn bản được giải mã, không phải byte được mã hóa.`bytes`là dữ liệu nhị phân bất biến.`bytearray`là dữ liệu nhị phân có thể thay đổi.`memoryview`cung cấp quyền truy cập không sao chép vào các đối tượng xuất bộ đệm.

Ranh gii gia văn bn và d liu nh phân rt rõ ràng: mã hóa`str`để sn xut`bytes`, và gii mã`bytes`để sn xut`str`. Ranh gii này rt cn thiết cho I/O tp chính xác, giao thc mng, gii mã ngun, mã m rng và các ng dng nhn biết Unicode.