XS-08 · Lưu và đọc lại bảng điểm bằng tệp CSV
Xem dạng PDFĐề
Phần cuối của bài toán xuyên suốt "Điểm học phần". Mang theo nguyên văn các hàm tinh_diem_hp, xep_loai (XS-04), chuan_hoa_ho_ten, ma_sv_hop_le, tach_dong (XS-06), tao_sinh_vien (XS-07).
Trong sách, chương trình quản lý tệp lop_hp.csv (mỗi dòng ma,ho_ten,diem_qt,diem_ck, không có dòng tiêu đề). Mỗi lần chạy:
- đọc tệp (chưa có thì coi như danh sách rỗng), bỏ qua các dòng hỏng và đếm chúng;
- thêm các sinh viên mới đọc từ bàn phím;
- ghi toàn bộ danh sách hợp lệ trở lại tệp;
- in bảng điểm.
Một dòng tệp là hỏng nếu: không có đúng 4 trường (tách bằng dấu phẩy), hoặc mã không gồm đúng 8 chữ số, hoặc một trong hai điểm không đổi được thành số bằng float(). Dòng trống cũng là dòng hỏng. Trước khi tách, mỗi dòng được bỏ khoảng trắng ở hai đầu (như dong.strip() trong sách).
Bản chấm tự động. Hệ thống chấm chỉ có bàn phím (stdin) và màn hình (stdout), không có tệp. Vì vậy:
- nội dung tệp
lop_hp.csvđược cho ngay trong dữ liệu vào (trước các sinh viên mới): thayopen()/for dong in fbằng việc đọc ~k~ dòng bằnginput();- thay việc ghi tệp bằng việc in nội dung tệp sẽ ghi: sau bảng điểm, in từng dòng CSV đúng như
ghi_danh_sachcủa sách sẽ ghi vào tệp.Các hàm
tach_dong_csv,doc_danh_sach,ghi_danh_sachgiữ nguyên ý tưởng của mục 9.7; chỉ đổi nguồn đọc và đích ghi.
Kiến thức dùng (Chương 9): split(","), ",".join(…), str() của số thực, try…except ValueError.
Dữ liệu vào
- Dòng 1: số nguyên ~k~ — số dòng của tệp
lop_hp.csvhiện có (~k = 0~: tệp chưa có hoặc rỗng). - ~k~ dòng tiếp theo: nguyên văn các dòng của tệp (có thể có dòng hỏng, dòng trống, khoảng trắng thừa).
- Dòng tiếp theo: số nguyên ~m~ — số sinh viên mới.
- ~m~ dòng tiếp theo: mỗi dòng một sinh viên mới theo dạng XS-06
ma ho ten diem_qt diem_ck.
Kết quả
- Dòng 1: số sinh viên đọc được từ tệp và số dòng hỏng, cách nhau một dấu cách (tính trước khi thêm sinh viên mới).
- Tiếp theo, bảng điểm: mỗi sinh viên một dòng
ma Ho Ten diem_hp loai(như XS-06) — sinh viên trong tệp trước, sinh viên mới sau, theo thứ tự đọc. - Cuối cùng, nội dung tệp sau khi ghi: mỗi sinh viên (cùng thứ tự) một dòng
ma,Ho Ten,diem_qt,diem_ck— họ tên đã chuẩn hóa, hai điểm thành phần viết nhưstr()của số thực (8.0,10.0,6.5).
Ràng buộc
- ~0 \le k \le 100~, ~0 \le m \le 100~.
- Mỗi dòng tệp dài không quá 100 ký tự ASCII in được (có thể là dòng trống). Họ tên trong tệp không chứa dấu phẩy.
- Ở dòng tệp có đủ 4 trường và mã đúng 8 chữ số: trường điểm nào đổi được bằng
float()thì là điểm trong ~[0; 10]~ viết dạng7,7.5(có thể kèm khoảng trắng), trường còn lại là chữ hoặc rỗng; nếu cả hai điểm đổi được thì họ tên có ít nhất một từ chữ cái không dấu, và mã không trùng với dòng hợp lệ khác. - Sinh viên mới: đúng dạng XS-06 (mã đúng 8 chữ số, họ tên ≥ 1 từ chữ cái, điểm
5,6.5hoặc6,5), mã chưa có trong tệp và đôi một khác nhau.
Ví dụ
Dữ liệu vào:
5
23010001,Nguyen Van An,7.5,8.0
23010002,Tran Thi Binh,6,5,7.0
2301002,Tran Thi Binh,6.5,7.0
23010004,Pham Quoc Dung,bon,4.0
23010005,Hoang Gia Han,5.0,3.0
1
23010006 Vu Ngoc Khanh 10 10
Kết quả:
2 3
23010001 Nguyen Van An 7.8 B
23010005 Hoang Gia Han 3.8 F
23010006 Vu Ngoc Khanh 10.0 A
23010001,Nguyen Van An,7.5,8.0
23010005,Hoang Gia Han,5.0,3.0
23010006,Vu Ngoc Khanh,10.0,10.0
Giải thích ví dụ
Tệp có 5 dòng (đúng ví dụ ở mục 9.7). Ba dòng hỏng:
- dòng 2 có 5 trường — điểm viết
6,5có dấu phẩy trùng với dấu phân cách (vì vậy tệp CSV luôn ghi dấu chấm); - dòng 3 có mã
2301002thiếu một chữ số; - dòng 4 có điểm
bon—float("bon")báoValueError, bắt bằngtry…except.
Nên dòng 1 là 2 3. Bảng điểm có hai sinh viên đọc từ tệp rồi đến sinh viên mới 23010006 (điểm gõ 10 10 → ~10{,}0~, loại A). Ba dòng cuối là nội dung tệp sau khi ghi: chỉ còn các dòng hợp lệ cộng dòng mới, điểm 10 của người mới ghi thành 10.0.
Các lần chạy "nối tiếp" của sách đều thử được bằng cách chép phần tệp in ra làm ~k~ dòng đầu của lần sau:
| Lần chạy | Tệp (k dòng) | Sinh viên mới | Dòng 1 kết quả |
|---|---|---|---|
| Bộ 1: lần đầu | (k = 0) | 23010001 Nguyen Van An 7.5 8.0, 23010003 le minh DUC 8,0 8.8 |
0 0 |
| Bộ 2: lần sau | hai dòng do Bộ 1 in ra | (m = 0) | 2 0 |
| Bộ 3: sau Ví dụ | ba dòng cuối của Ví dụ | (m = 0) | 3 0 |
Lưu ý khi nộp
- Dòng trống được đếm là hỏng (khác khuôn ở mục 9.3).
- Kiểm đúng 4 trường:
len(phan) != 4, không phảilen(phan) < 4. - Ghi tệp bằng giá trị đã chuẩn hóa trong dict: họ tên sau
chuan_hoa_ho_ten, điểm làstr(float)— đừng ghi lại chuỗi gốc (8,0sẽ làm hỏng tệp). - Khác sách về thứ tự in: trong mục 9.7,
ghi_danh_sachđược gọi trước vòng in bảng điểm; ở bản chấm tự động này phải in bảng điểm trước, rồi mới in nội dung tệp (như mục Kết quả). Chép lời giải sách rồi chỉ đổif.writethànhprintmà giữ nguyên thứ tự gọi sẽ bị Wrong Answer. - Bỏ khoảng trắng cả dòng (
dong.strip()) rồi mới tách; đừngstrip()từng trường trước khi kiểm mã — dòng23010002 ,...có mã23010002(9 ký tự) là hỏng. Còn điểm có khoảng trắng quanh (7.5) vẫn hợp lệ vìfloat()tự bỏ khoảng trắng; đừng kiểm điểm bằngisdigit(). try … except ValueErrorphải bọc cả hai lầnfloat()(điểm cuối kỳ cũng có thể là chữ hoặc rỗng).- Hệ thống so từng dòng, từng ký tự (chỉ bỏ qua khoảng trắng ở cuối dòng và dòng trống): giữa các từ của họ tên, giữa các phần trên một dòng phải đúng một dấu cách —
title()mà quên gộp khoảng trắng (Le Minh Duc) sẽ bị Wrong Answer. - Không in gì ngoài ba phần trên (không in nhãn, không in dòng gỡ lỗi).
Nguồn trong sách: Bài XS-08, mục 9.7, giáo trình Lập trình cơ sở với Python — TS. Nguyễn Quốc Long · Mức: XS (bài toán xuyên suốt, phần 8/8 — bản chấm tự động)