Trong bài này
Lan ghi mã sách PY2026 lên một thẻ. Lan muốn lấy hai chữ đầu để nhận biết môn học và kiểm tra bốn chữ số cuối. Python có thể đọc từng ký tự và tạo chuỗi mới từ mã đó.
Chỉ số chọn một ký tự theo vị trí
Mã sách có sáu ký tự. Hãy lấy ký tự đầu và ký tự ở vị trí thứ ba:
ma = "PY2026"
print(ma[0])
print(ma[2])P 2
Chỉ số (index) là số dùng để chọn vị trí. Python bắt đầu đếm từ 0: ma[0] là P, còn ma[2] là 2. Dấu ngoặc vuông đặt sau chuỗi hoặc tên biến chứa chuỗi.
| Bước | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| ma | P | Y | 2 | 0 | 2 | 6 |
Bạn có thể đếm từ cuối bằng chỉ số âm. -1 chọn ký tự cuối, -2 chọn ký tự liền trước:
ma = "PY2026"
print(ma[-1])
print(ma[-2])6 2
Chỉ số -1 cho 6; -2 cho 2. Chỉ số âm không bắt đầu bằng -0, vì -0 bằng 0.
Hàm len() cho biết số ký tự, kể cả dấu cách. Chuỗi rỗng có độ dài bằng 0:
ten = "An Binh"
print(len(ten))
print(len(""))7 0
ten có bảy ký tự, gồm một dấu cách. Với chuỗi khác rỗng, chỉ số cuối là len(ten) - 1. Truy cập ngoài phạm vi gây lỗi:
ma = "PY2026"
print(ma[6])Lỗi khi chạy, ở dòng 2
IndexError: string index out of range
Python báo IndexError: sáu ký tự có chỉ số từ 0 đến 5. Với chuỗi rỗng, cả [0] và [-1] đều không hợp lệ. Kiểm tra độ dài trước khi truy cập dữ liệu chưa biết.
Đối với dữ liệu nhập, chương trình có thể chọn thông báo riêng khi người dùng để trống. Nhánh còn lại chỉ truy cập khi đã biết chuỗi có ký tự:
Ke A
nhan = input()
if len(nhan) > 0:
print(nhan[-1])
else:
print("Nhan rong")A
Với dữ liệu này, nhánh đầu chọn A. Nếu dòng vào rỗng, nhánh else chạy và chương trình không cố truy cập một vị trí không tồn tại.
Cắt chuỗi lấy một đoạn hoặc đảo thứ tự
Hãy lấy hai chữ đầu của mã:
ma = "PY2026"
print(ma[0:2])PY
Cắt chuỗi (slicing) tạo chuỗi mới từ các vị trí được chọn. Trong ma[0:2], vị trí đầu 0 được lấy, còn vị trí cuối 2 không được lấy. Kết quả là PY, không có ký tự 2. Tương tự, ma[1:4] lấy các vị trí 1, 2, 3 và tạo chuỗi Y20:
| Bước | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| ma | P | Y | 2 | 0 | 2 | 6 |
Bạn có thể bỏ đầu hoặc cuối: đầu mặc định là 0, cuối mặc định là hết chuỗi. Đầu bằng cuối tạo chuỗi rỗng.
ma = "PY2026"
print(ma[:2])
print(ma[2:])
print(ma[3:3])PY 2026
Với dữ liệu trên, ma[:2] là PY, ma[2:] là 2026; dòng thứ ba rỗng. Cận cắt vượt độ dài được giới hạn về đầu hoặc cuối, khác với truy cập một chỉ số vượt phạm vi.
Thêm dấu hai chấm thứ hai để chọn bước (step). Bước 2 lấy cách một ký tự:
ma = "PY2026"
print(ma[::2])P22
Các chỉ số được chọn là 0, 2, 4. Bước âm đi từ phải sang trái. Khi bỏ cả hai cận, [::-1] đảo chuỗi:
ma = "PY2026"
print(ma[::-1])
print(ma[4:1:-1])6202YP 202
Lát cắt ma[4:1:-1] lấy các vị trí 4, 3, 2 và tạo chuỗi 202. Vị trí 1 không được lấy. Nếu đặt bước bằng 0, Python báo ValueError.
Bạn cũng có thể dùng cận âm để bỏ phần ở cuối. Ví dụ sau giữ phần trước hai ký tự cuối của một mã:
ma = "KE2026"
print(ma[:-2])KE20
Kết quả là KE20. Vị trí -2 không được lấy, cũng như mọi cận cuối khác. Cách này không thay đổi ma; một lát cắt tạo giá trị mới.
Duyệt và kiểm tra sự xuất hiện của ký tự
Một nhãn hàng có thể chứa nhiều chữ a. Duyệt từng ký tự để đếm:
nhan = "banana"
dem = 0
for ky_tu in nhan:
if ky_tu == "a":
dem = dem + 1
print(dem)3
Mỗi lượt, ky_tu nhận một ký tự theo thứ tự từ trái sang phải. Biến dem tăng khi ký tự bằng a. Chuỗi rỗng không tạo lượt lặp nào.
Toán tử in kiểm tra một chuỗi con có xuất hiện trong chuỗi khác hay không:
nhan = "banana"
print("ana" in nhan)
print("A" in nhan)True False
Kết quả thứ nhất là True; kết quả thứ hai là False vì chữ hoa và chữ thường khác nhau. in kiểm tra sự xuất hiện liên tiếp, không cho biết vị trí. Chuỗi rỗng được xem là có trong mọi chuỗi, kể cả chuỗi rỗng.
Phương thức tạo chuỗi mới thay vì sửa chuỗi gốc
Hãy đổi cách viết nhãn và quan sát cả giá trị cũ:
nhan = "Sach Moi"
hoa = nhan.upper()
print(hoa)
print(nhan)SACH MOI Sach Moi
Phương thức (method) là thao tác gọi sau dấu chấm của một giá trị. upper() trả chuỗi chữ hoa; lower() trả chuỗi chữ thường. Hai phương thức không tự gán lại biến ban đầu.
nhan = "Sach Moi"
print(nhan.lower())sach moi
Để kiểm tra không phân biệt hoa thường, hãy đưa nội dung và phần cần tìm về cùng kiểu chữ:
nhan = "BANANA"
print("a" in nhan.lower())True
nhan.lower() tạo banana, nên phép kiểm tra tìm thấy a và trả True.
Chuỗi là kiểu bất biến (immutable): không thể gán trực tiếp vào một vị trí. Ví dụ sau cố ý gây lỗi:
nhan = "Sach"
nhan[0] = "s"Lỗi khi chạy, ở dòng 2
TypeError: 'str' object does not support item assignment
Python báo TypeError. Muốn thay đổi nội dung, tạo chuỗi mới rồi gán lại tên. Dùng phép cắt và nối để giữ phần còn lại:
nhan = "Sach"
nhan = "s" + nhan[1:]
print(nhan)sach
strip() bỏ khoảng trắng ở hai đầu, không bỏ khoảng trắng bên trong. replace(cu, moi) tạo chuỗi thay các lần xuất hiện không chồng lấn của phần cũ:
nhan = " ke A "
sach = nhan.strip()
print("[" + sach + "]")
print(sach.replace(" ", "-"))[ke A] ke-A
strip() không xóa dấu cách giữa ke và A. Nếu muốn giữ kết quả cho bước sau, hãy gán kết quả của phương thức vào biến.
Các phương thức tìm và kiểm tra nội dung
Với một mã có thể lặp ký tự, count() đếm số lần xuất hiện không chồng lấn:
ma = "ABABABA"
print(ma.count("ABA"))2
Kết quả là 2: lần tìm tiếp theo bắt đầu sau phần đã đếm, nên không tính các lần chồng lên nhau. Để tìm vị trí đầu tiên, dùng find():
ma = "ABABABA"
print(ma.find("BA"))
print(ma.find("XY"))1 -1
Vị trí tìm thấy là 1; khi không thấy, find() trả -1. Giá trị 0 cũng có thể là vị trí tìm thấy, nên hãy so sánh với -1 thay vì coi kết quả là điều kiện đúng sai.
startswith() kiểm tra phần đầu chuỗi. Hãy phân biệt bắt đầu bằng PY với chỉ chứa PY:
ma = "APY12"
print(ma.startswith("PY"))
print("PY" in ma)False True
startswith("PY") cho False, còn phép kiểm tra chứa cho True. Phần cần tìm có mặt nhưng không nằm ở đầu.
isdigit() kiểm tra chuỗi không rỗng gồm các ký tự chữ số; isalpha() kiểm tra chuỗi không rỗng gồm các ký tự chữ cái:
print("2026".isdigit())
print("An".isalpha())
print("A2".isalpha())
print("".isdigit())True True False False
A2 không chỉ gồm chữ cái; chuỗi rỗng cũng cho False. Dấu cách và dấu trừ không phải chữ số, nên "-2".isdigit() là False.
split tách các phần và join nối chúng
Một dòng có các từ cách nhau bằng khoảng trắng. Dùng split() để tách:
dong = " sach moi "
cac_tu = dong.split()
print(cac_tu)['sach', 'moi']
Kết quả là một dãy các chuỗi; bạn sẽ học chi tiết danh sách ở Bài 10. Khi không truyền dấu phân cách, split() bỏ khoảng trắng hai đầu và gộp khoảng trắng liên tiếp khi tách. Dòng chỉ có khoảng trắng cho dãy rỗng.
Bạn cũng có thể chỉ rõ dấu phân cách:
dong = "do,,xanh"
print(dong.split(","))['do', '', 'xanh']
Hai dấu phẩy liền nhau tạo một phần rỗng. Điều này khác split() không đối số: dấu phân cách tường minh không tự gộp.
Nếu dấu phân cách nằm ở đầu hoặc cuối, phần ở phía ngoài cũng rỗng. Chẳng hạn ",do,".split(",") tạo ba phần: phần rỗng, do, rồi phần rỗng. Chọn cách tách theo ý nghĩa dữ liệu; không tự giả định rằng mọi phần đều có nội dung.
Để nối các phần thành chuỗi, gọi join() trên chuỗi dùng làm dấu ngăn:
dong = " sach moi "
cac_tu = dong.split()
nhan = "-".join(cac_tu)
print(nhan)sach-moi
Chuỗi "-" nằm giữa các phần, không tự thêm ở đầu hoặc cuối. join() cần các phần đều là chuỗi; dữ liệu số phải đổi sang chuỗi trước. Nối dãy rỗng tạo chuỗi rỗng.
Mã ký tự giúp chuyển giữa ký tự và số
Python gán một số cho mỗi ký tự Unicode. ord() nhận đúng một ký tự và trả mã số:
print(ord("A"))
print(ord("B"))65 66
Hai mã là 65 và 66. ord() không nhận chuỗi rỗng hoặc chuỗi nhiều ký tự. chr() thực hiện chiều ngược lại với mã Unicode hợp lệ:
print(chr(65))
print(chr(ord("A") + 2))A C
Kết quả là A và C. Với chữ tiếng Anh viết hoa, các mã A đến Z liên tiếp. Chữ thường a đến z cũng liên tiếp, nhưng mã của a khác mã của A. chr() báo ValueError nếu mã ngoài phạm vi Unicode hợp lệ.
F-string căn nội dung trong một độ rộng
Một bảng tên cần hai cột rộng bằng nhau. Hãy đặt nội dung trong trường rộng tám ký tự:
ten = "Lan"
print(f"|{ten:<8}|")
print(f"|{ten:>8}|")|Lan | | Lan|
Trong f-string, :<8 căn trái và :>8 căn phải trong độ rộng tối thiểu 8. Dấu | giúp nhìn thấy phần dấu cách được thêm.
Để căn giữa, dùng ^. Nếu nội dung dài hơn độ rộng, Python giữ đủ nội dung thay vì cắt:
print(f"|{'An':^8}|")
print(f"|{'Thu vien':>4}|")| An | |Thu vien|
Độ rộng là mức tối thiểu, không phải giới hạn độ dài. Nếu cần rút nội dung, hãy cắt chuỗi trước khi định dạng.
Khi đề yêu cầu đầu ra chính xác, hãy tính cả các dấu cách do căn lề tạo ra.
Lỗi thường gặp
| Lỗi | Vì sao sai | Cách sửa |
|---|---|---|
Dùng s[len(s)] | Chỉ số cuối nhỏ hơn độ dài một đơn vị | Dùng s[-1] khi chuỗi không rỗng |
Nghĩ s[1:3] gồm vị trí 3 | Cận cuối không được lấy | Chọn cận cuối sau vị trí mong muốn |
Gán s[0] = "A" | Chuỗi không cho sửa từng vị trí | Tạo chuỗi mới rồi gán lại |
Gọi s.strip() mà bỏ kết quả | Phương thức trả chuỗi mới | Gán s = s.strip() |
Dùng if s.find(x) để kiểm tra | Vị trí 0 có giá trị sai trong điều kiện | So sánh với -1 hoặc dùng x in s |
Gọi cac_tu.join("-") | Dấu ngăn phải đứng trước .join() | Dùng "-".join(cac_tu) |
Cho bước cắt bằng 0 | Không thể tiến hoặc lùi bằng bước không | Chọn bước khác 0 |
Tóm tắt
- Chỉ số bắt đầu từ
0; chỉ số âm đếm từ cuối.len()đếm ký tự. - Lát cắt không lấy cận cuối;
[::-1]tạo chuỗi đảo. - Duyệt bằng
for;inkiểm tra sự xuất hiện của chuỗi con. - Các phương thức biến đổi trả chuỗi mới; chuỗi gốc không bị sửa.
split()tách vàjoin()nối;ord()vàchr()đổi giữa ký tự và mã.- F-string dùng
<,>hoặc^để căn theo độ rộng tối thiểu.