XS-08 · Lưu và đọc lại bảng điểm bằng tệp CSV

Xem dạng PDF

Gửi bài giải

Điểm: 1,00
Giới hạn thời gian: 1.0s
Giới hạn bộ nhớ: 256M
Input: stdin
Output: stdout

Tác giả:
Nguồn bài:
Sách "Lập trình cơ sở với Python"
Dạng bài
Ngôn ngữ cho phép
Python

Đề

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:

  1. đọ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;
  2. thêm các sinh viên mới đọc từ bàn phím;
  3. ghi toàn bộ danh sách hợp lệ trở lại tệp;
  4. 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): thay open()/for dong in f bằng việc đọc ~k~ dòng bằng input();
  • 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_sach của sách sẽ ghi vào tệp.

Các hàm tach_dong_csv, doc_danh_sach, ghi_danh_sach giữ 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.csv hiệ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ả

  1. 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).
  2. 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.
  3. 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ạng 7, 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.5 hoặc 6,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,5 có 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ã 2301002 thiếu một chữ số;
  • dòng 4 có điểm bon — float("bon") báo ValueError, bắt bằng try…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ải len(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,0 sẽ 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ỉ đổi f.write thành print mà 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; đừng strip() từng trường trước khi kiểm mã — dòng 23010002 ,... 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ằng isdigit().
  • try … except ValueError phải bọc cả hai lần float() (đ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)


Đang tải...