Cơ chế mã hóa ký tự và thao tác với chuỗi trong Python

Tổng quan về mã hóa ký tự

Máy tính chỉ hiểu các con số, do đó mọi văn bản đều phải được chuyển đổi thành dãy số trước khi xử lý. Đơn vị cơ bản nhất là bit, và 8 bit tạo thành một byte. Một byte có thể biểu diễn số nguyên tối đa là 255.

Trong giai đoạn đầu, hệ thống ASCII được tạo ra với 127 ký tự cơ bản (chữ cái Latinh, số và ký hiệu đặc biệt). Ví dụ, ký tự A có giá trị 65. Tuy nhiên, ASCII không đủ để biểu diễn các ngôn ngữ có bộ ký tự lớn như tiếng Trung, tiếng Nhật hay tiếng Việt.

Sự ra đời của các chuẩn riêng lẻ như GB2312, Shift_JIS dẫn đến tình trạng xung đột và lỗi hiển thị (loạn mã) khi trao đổi dữ liệu đa ngôn ngữ. Để giải quyết vấn đề này, Unicode được phát triển nhằm thống nhất tất cả các ký tự của mọi ngôn ngữ trên thế giới vào một bảng mã duy nhất.

Mặc dù Unicode giải quyết được vấn đề loạn mã, nhưng việc sử dụng cố định 2 hoặc 4 byte cho mỗi ký tự gây lãng phí dung lượng, đặc biệt với văn bản chủ yếu là tiếng Anh. Do đó, UTF-8 xuất hiện như một giải pháp mã hóa độ dài thay thế. UTF-8 sử dụng 1 byte cho ký tự ASCII, 3 byte cho các ký tự phổ biến như tiếng Việt hay tiếng Trung, và tối đa 4 byte cho các ký tự hiếm.

Ký tựASCIIUnicodeUTF-8
Z0101101000000000 0101101001011010
ViệtKhông hỗ trợ00100001 0000010111100010 10000100 10000101

Trong thực tế phát triển phần mềm, bộ nhớ trong (RAM) thường lưu trữ chuỗi dưới dạng Unicode, trong khi dữ liệu lưu trữ trên ổ cứng hoặc truyền qua mạng sẽ được chuyển đổi sang UTF-8 để tối ưu hóa dung lượng.

Xử lý chuỗi trong Python

Từ phiên bản Python 3, mọi chuỗi văn bản (str) đều được lưu trữ dưới dạng Unicode, hỗ trợ đa ngôn ngữ mặc định.

# In ra chuỗi chứa ký tự đặc biệt
message = "Lập trình Python rất thú vị!"
print(message)

Để lấy mã số nguyên của một ký tự, ta dùng hàm ord(), và ngược lại, dùng chr() để chuyển mã số thành ký tự:

# Chuyển đổi giữa ký tự và mã số
char_code = ord('Z')  # Trả về 90
print(char_code)

decoded_char = chr(89)  # Trả về 'Y'
print(decoded_char)

Ngoài ra, bạn có thể biểu diễn ký tự bằng mã hexa trong chuỗi:

# Sử dụng mã Unicode hexa
text = '\u0050\u0079\u0074\u0068\u006f\u006e'
print(text)  # Output: Python

Khi truyền tải dữ liệu qua mạng hoặc ghi vào file, chuỗi str cần được chuyển đổi thành kiểu bytes. Kiểu bytes được ký hiệu bằng tiền tố b.

# Phân biệt str và bytes
string_data = "ABC"
bytes_data = b"XYZ"

# Mã hóa str sang bytes
encoded_ascii = string_data.encode('ascii')
encoded_utf8 = "Mã hóa".encode('utf-8')

print(encoded_ascii)  # b'ABC'
print(encoded_utf8)   # b'M\xc3\xa3 h\xc3\xb3a'

Nếu cố gắng mã hóa ký tự không thuộc bảng ASCII bằng chuẩn ASCII, Python sẽ ném ra lỗi UnicodeEncodeError.

Ngược lại, để giải mã bytes thành str, ta sử dụng phương thức decode():

# Giải mã bytes sang str
raw_bytes = b"Network"
decoded_text = raw_bytes.decode('ascii')

utf8_bytes = b'M\xc3\xa3 h\xc3\xb3a'
decoded_utf8 = utf8_bytes.decode('utf-8')

print(decoded_text)   # Network
print(decoded_utf8)   # Mã hóa

Nếu luồng byte chứa dữ liệu không hợp lệ, bạn có thể bỏ qua chúng bằng tham số errors='ignore':

invalid_bytes = b'M\xc3\xa3\xff'
safe_decode = invalid_bytes.decode('utf-8', errors='ignore')
print(safe_decode)  # Mã

Hàm len() hoạt động khác nhau tùy thuộc vào kiểu dữ liệu. Với str, nó đếm số lượng ký tự. Với bytes, nó đếm số lượng byte:

word_str = "Code"
word_bytes = word_str.encode('utf-8')

print(len(word_str))    # 4 (ký tự)
print(len(word_bytes))  # 4 (byte)

vn_str = "Việt"
vn_bytes = vn_str.encode('utf-8')

print(len(vn_str))    # 4 (ký tự)
print(len(vn_bytes))  # 6 (byte, do ký tự 'ệ' tốn 3 byte)

Khi làm việc với file mã nguồn Python chứa ký tự đa ngôn ngữ, hãy đảm bảo trình soạn thảo lưu file dưới dạng UTF-8 và thêm khai báo sau vào đầu file:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

Định dạng chuỗi

Python hỗ trợ nhiều cách để chèn biến vào chuỗi. Phương pháp truyền thống sử dụng toán tử %, tương tự như ngôn ngữ C.

# Định dạng cơ bản với %
name = "Alice"
age = 28
greeting = "Xin chào, %s. Bạn %d tuổi." % (name, age)
print(greeting)

Các trình giữ chỗ (placeholder) phổ biến bao gồm:

Trình giữ chỗÝ nghĩa
%dSố nguyên
%fSố thực
%sChuỗi (có thể dùng cho mọi kiểu dữ liệu)
%xSố nguyên hệ 16

Để in ra ký tự % trong chuỗi, hãy sử dụng %%:

discount = 20
print("Giảm giá: %d %%" % discount)  # Giảm giá: 20 %

Một cách tiếp cận hiện đại và linh hoạt hơn là sử dụng phương thức format():

# Sử dụng format()
product = "Laptop"
price = 1250.75
output = "Sản phẩm: {0}, Giá: {1:.2f} USD".format(product, price)
print(output)

Bài tập thực hành

Nhiệt độ trung bình của một thành phố tăng từ 24.5 độ C lên 26.2 độ C. Hãy tính phần trăm mức tăng và in ra màn hình với định dạng 'x.x%' (làm tròn 1 chữ số thập phân).

# -*- coding: utf-8 -*-

old_temp = 24.5
new_temp = 26.2

# Tính phần trăm tăng trưởng
increase_percent = ((new_temp - old_temp) / old_temp) * 100

# Định dạng và in kết quả
print("Mức tăng nhiệt độ: %.1f%%" % increase_percent)

Thẻ: python character-encoding UTF-8 string-formatting

Đăng vào ngày 11 tháng 9 lúc 01:33