Xử lý văn bản là việc gần như chương trình nào cũng phải làm. Python có bộ công cụ chuỗi rất phong phú — bài này đi qua những thứ dùng nhiều nhất.
f-string: cách định dạng nên dùng
ten = "Lan"
diem = 8.567
print(f"{ten} được {diem} điểm")
print(f"{ten} được {diem:.1f} điểm") # làm tròn 1 chữ số
print(f"{diem:>10.2f}") # căn phải, rộng 10
print(f"{1234567:,}") # 1,234,567
print(f"{0.856:.1%}") # 85.6%
Từ Python 3.8, thêm dấu = để in cả tên biến — rất tiện khi gỡ lỗi:
print(f"{diem=}") # diem=8.567
print(f"{diem*2=:.2f}") # diem*2=17.13
Căn chỉnh khi in bảng
hang_hoa = [("Bàn phím", 450_000), ("Chuột", 250_000), ("Màn hình", 3_200_000)]
for ten, gia in hang_hoa:
print(f"{ten:<15} {gia:>12,}đ")
Bàn phím 450,000đ
Chuột 250,000đ
Màn hình 3,200,000đ
Các thao tác thường dùng
s = " Xin chào Việt Nam "
s.strip() # bỏ khoảng trắng hai đầu
s.lstrip() # bỏ bên trái
s.lower() # chữ thường
s.upper() # CHỮ HOA
s.title() # Viết Hoa Đầu Từ
s.replace("chào", "gửi")
s.split() # ['Xin', 'chào', 'Việt', 'Nam']
"-".join(["a", "b", "c"]) # 'a-b-c'
Kiểm tra nội dung
ten_file = "bao_cao.pdf"
ten_file.endswith(".pdf") # True
ten_file.startswith("bao") # True
"cao" in ten_file # True
ten_file.count("a") # 3
ten_file.find("cao") # 4, trả -1 nếu không thấy
Muốn kiểm tra nhiều đuôi file cùng lúc, truyền tuple:
if ten_file.endswith((".jpg", ".png", ".webp")):
print("Đây là ảnh")
Chuỗi là bất biến
Mọi thao tác đều tạo chuỗi mới, không sửa chuỗi cũ:
s = "python"
s.upper() # trả về 'PYTHON'
print(s) # vẫn là 'python'
s = s.upper() # phải gán lại
Điều này có hệ quả về hiệu năng. Nối chuỗi trong vòng lặp rất chậm vì mỗi lần đều tạo chuỗi mới:
# Chậm với dữ liệu lớn
ket_qua = ""
for dong in danh_sach:
ket_qua += dong + "\n"
# Nhanh hơn nhiều
ket_qua = "\n".join(danh_sach)
Xử lý tiếng Việt
Python 3 làm việc với Unicode nên tiếng Việt hoạt động bình thường. Nhưng có vài điểm cần biết.
Chuẩn hóa dạng Unicode
Chữ “ế” có thể được lưu bằng một ký tự, hoặc bằng “e” cộng hai dấu rời. Nhìn giống hệt nhau nhưng máy coi là khác:
import unicodedata
a = "tiếng" # dạng dựng sẵn
b = "tiếng" # dạng tổ hợp (nhìn y hệt)
print(a == b) # có thể False
print(unicodedata.normalize("NFC", a) ==
unicodedata.normalize("NFC", b)) # True
Khi so sánh hoặc lưu văn bản tiếng Việt từ nhiều nguồn, hãy chuẩn hóa về NFC trước. Đây là nguyên nhân của nhiều lỗi “tìm không ra dù nhìn giống nhau”.
Bỏ dấu tiếng Việt
Hữu ích khi tạo đường dẫn thân thiện hoặc tìm kiếm không dấu:
import unicodedata, re
def bo_dau(s):
s = unicodedata.normalize("NFD", s)
s = "".join(c for c in s if unicodedata.category(c) != "Mn")
return s.replace("đ", "d").replace("Đ", "D")
def tao_slug(s):
s = bo_dau(s).lower()
s = re.sub(r"[^a-z0-9]+", "-", s)
return s.strip("-")
print(tao_slug("Lập trình Python cơ bản"))
# lap-trinh-python-co-ban
Chú ý phải xử lý riêng chữ “đ” — nó không phải là “d” kèm dấu nên bước chuẩn hóa không tách ra được.
Biểu thức chính quy
Khi thao tác chuỗi thông thường không đủ:
import re
van_ban = "Liên hệ: an@example.com hoặc binh@company.vn"
emails = re.findall(r"[\w.+-]+@[\w-]+\.[\w.]+", van_ban)
print(emails)
# Thay thế
sach = re.sub(r"\d{4,}", "[đã ẩn]", "Số thẻ 1234567890")
# Kiểm tra định dạng
if re.fullmatch(r"0\d{9}", so_dien_thoai):
print("Số điện thoại hợp lệ")
Khi dùng cùng một mẫu nhiều lần, hãy biên dịch trước:
MAU_EMAIL = re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+")
for dong in hang_trieu_dong:
if MAU_EMAIL.search(dong):
...
Lời khuyên cuối: đừng dùng biểu thức chính quy để phân tích HTML hay JSON. Có thư viện chuyên dụng cho việc đó, và chúng xử lý đúng những trường hợp mà regex sẽ sai một cách âm thầm.