py 作業登記器(C 程序設計)
[編輯] [转简体] (简体译文)
|
作者:huidong
| 分類:【編程】python
[
16 瀏覽
0 評論
5 贊
5 踩
]
概要
用於登記作業提交情況
正文
###################################### # # C 程序設計 作業登記器 # # by huidong <mailhuid@163.com> # 2024.10.12 Python 3.9(64-bit) # import csv from gettext import find from msvcrt import getch import os import tkinter as tk from tkinter import filedialog # 學生信息記錄文件 student_data_path = "students_data.csv" ############## 文件操作函數 ############## # 讓用戶選擇文件夾(未選擇返回 False) def select_folder(): # 创建一个隐藏的主窗口 root = tk.Tk() root.withdraw() # 隐藏主窗口 # 打开文件夹选择对话框 folder_path = filedialog.askdirectory() root.destroy() # 銷燬窗口 # 检查用户是否选择了文件夹 if folder_path: return folder_path else: print("未選擇文件夾") return False # 查詢文件夾中的所有文件(成功則返回文件名列表,失敗返回 False) def get_filenames_in_folder(folder_path : str): try: # 获取文件夹中的所有文件和子文件夹 files_and_dirs = os.listdir(folder_path) # 过滤出文件 files = [f for f in files_and_dirs if os.path.isfile(os.path.join(folder_path, f))] return files except Exception as e: print(f"獲取文件夾內容時出錯: {e}") return False # # 從記錄的數據中讀取學生信息列表 # # 包含以下信息: # # npuid 學生學號 # # name 學生姓名 # # submit 交作業次數 # def read_students_info(): # students = [] # with open(student_data_path, mode='r', encoding='utf-8') as file: # for line in file: # parts = line.strip().split(',') # students.append({ # 'npuid' : parts[0], # 學號 # 'name' : parts[1], # 姓名 # 'submit' : int(parts[2]) # 交作業次數 # }) # return students # 從記錄的數據中讀取學生信息列表 # 包含以下信息: # npuid 學生學號 # name 學生姓名 # submit 交作業次數 def read_students_info(): students = [] with open(student_data_path, mode='r', encoding='utf-8', newline='') as file: reader = csv.DictReader(file, fieldnames=['npuid', 'name', 'submit']) is_first_row = True # 跳過第一行的表頭 for row in reader: if is_first_row: is_first_row = False; continue row['submit'] = int(row['submit']) # 提交次數字段轉整數 students.append(row) return students # # 將學生信息列表寫入數據記錄中 # def write_students_info(students : list): # with open(student_data_path, mode='w', encoding='utf-8') as file: # for student in students: # file.write(f"{student['npuid']},{student['name']},{student['submit']}\n") # 將學生信息列表寫入數據記錄中 def write_students_info(students: list): with open(student_data_path, mode='w', encoding='utf-8', newline='') as file: fieldnames = ['npuid', 'name', 'submit'] writer = csv.DictWriter(file, fieldnames=fieldnames) # 寫入表頭 writer.writeheader() # 寫入數據行 for student in students: writer.writerow(student) ############## 算法相關函數 ############## # 從文件名(不包括 .*)中解碼學生信息(返回 (學號, 姓名) 的元組,若學號不存在則元組字符串爲空) def decode_filename(filename: str): # 第一步,通過學號 2024 開頭,直接讀 10 位數字,學號讀出來一般都不會有問題 # 要是連學號都沒有,那就不讀了 student_id = "" begin_student_id = filename.find("2024") if begin_student_id != -1: end_student_id = begin_student_id + 10 student_id = filename[begin_student_id : end_student_id] else: return "", "" # 第二步,收集姓名,對文件名的要求是: # 作業名稱可以沒有,但是有的話一定要放在學號和名字之後 # 分隔符可以是 ' ', '_', '-' 或者直接依靠學號的數字進行分隔 student_name = "" separator = {' ', '_', '-'} if begin_student_id == 0: # 如果一開始就是學號,那麼認爲下一段中文是姓名 for ch in filename[10:]: if ch in separator: if student_name.__len__(): break else: continue student_name += ch else: # 否則一開始就是姓名 for ch in filename[:begin_student_id]: if ch in separator: if student_name.__len__(): break else: continue student_name += ch return student_id, student_name # 根據文件全名獲取作業信息 # 返回作業信息,包含以下內容: # filename 作業文件名稱 # file_extension 作業文件擴展名 # npuid 學生學號 # name 學生姓名 def get_homework_info(file_fullname : str): file_name, file_extension = os.path.splitext(file_fullname) # 分離文件名和後綴 student_id, student_name = decode_filename(file_name) # 從文件名解碼學生學號和姓名 homework_info = { # 記錄這一份作業的信息 'filename': file_name, 'file_extension' : file_extension, 'npuid': student_id, 'name' : student_name } return homework_info ############## 主要模塊函數 ############## # 審覈新的學生(作業)信息,返回審覈結果(bool) def review_student_info(homework_list : list): print("") print("============ 學生(作業)信息 ============") for homework in homework_list: print( homework['npuid'], homework['name'] + '\t\t' + '(' + homework['filename'] + homework['file_extension'] + ')') print(f"總計:{len(homework_list)} 條信息") print("==========================================") print("審覈通過?(y / n)") print("") while True: ch = getch().decode() if ch == 'n': return False elif ch == 'y': return True # 登記作業(完成此次登記返回 True,放棄此次登記返回 False) def register(): folder = select_folder() # 選擇作業文件夾 if folder == False: return False filenames = get_filenames_in_folder(folder) # 讀取文件夾下的所有文件 # 讀入已有學生數據 students_info = read_students_info() # 作業分揀箱 list_noID = [] # 沒有寫學號的作業 list_new = [] # 屬於新同學的作業 list_old = [] # 屬於之前有完整記錄(學號和姓名)的學生的作業 list_noname_old = [] # 屬於之前有學號但沒登記姓名的學生的作業 # 分揀作業 for filename in filenames: homework_info = get_homework_info(filename) if homework_info['npuid'] == '': # 沒寫學號的作業不收 list_noID.append(homework_info) # 寫了學號的作業要進行進一步分揀 else: isNew = True # 是否爲新學生 isNoName = False #(對於老生)是否登記有他的名字 for student in students_info: # 查詢登記在冊的學生信息表 if student['npuid'] == homework_info['npuid']: isNew = False # 查到此人,則非新學生 isNoName = student['name'] == '' # 是新生 if isNew: list_new.append(homework_info) # 是之前沒寫過名字的老生 elif isNoName: list_noname_old.append(homework_info) # 是信息齊全的老生 else: list_old.append(homework_info) ####### 作業分揀完成,以下進行學生信息的新增和補充 ####### # 登記新同學信息 if list_new.__len__(): print("【審覈】有新同學信息需要審覈:") print("【備註】以下是所有新同學提交的作業,可能包含同一人的重複提交,實際寫入學生數據時會去重。") if not review_student_info(list_new): return False # 登記這些同學的信息 unique_npuid_record = [] # 防止重複添加的學號唯一記錄列表 for homework in list_new: # 防止重複添加 if homework['npuid'] in unique_npuid_record: continue unique_npuid_record.append(homework['npuid']) student = { 'npuid' : homework['npuid'], 'name' : homework['name'], 'submit' : 0 } students_info.append(student) # 若存在曾經沒寫名字的老生交作業,則對這部分老生重新登記名字 if list_noname_old.__len__(): list_have_name = [] # 從裏面找出現在寫了名字的 for homework in list_noname_old: if homework['name'] != '': list_have_name.append(homework) if list_have_name.__len__(): print("【審覈】有曾經沒寫過名字的老生補充了他們的名字,需要審覈:") if not review_student_info(list_have_name): return False # 更新這些同學的信息 for homework in list_have_name: for student in students_info: if student['npuid'] == homework['npuid']: student['name'] = homework['name'] ####### 學生信息處理完成,以下進行作業登記 ####### homework_all = list_new + list_old + list_noname_old npuid_submit = [] # 記錄提交過有效作業的學生學號 valid_homework = [] # 提交有效的作業 invalid_homework = [] # 提交無效的作業 # 合法後綴名 valid_ext = ('.c', '.cpp', '.exe') # 登記作業 for homework in homework_all: # 後綴名合法才可提交 ext = homework['file_extension'] if ext not in valid_ext: invalid_homework.append(homework) continue # 在同一次登記中,一個人提交多次作業,只登記第一次 if homework['npuid'] not in npuid_submit: npuid_submit.append(homework['npuid']) valid_homework.append(homework) # 存在無學號作業 if list_noID.__len__(): print("【審覈】存在無學號的作業,需要審覈:") if not review_student_info(list_noID): return False # 存在無效作業 if invalid_homework.__len__(): print("【審覈】存在文件後綴名錯誤的作業,需要審覈:") if not review_student_info(invalid_homework): return False # 存在有效作業 if valid_homework.__len__(): print("【審覈】以下是提交有效的作業,需要審覈:") print("【備註】提交有效,即去重了無學號、後綴名錯誤、重複提交的作業。") if not review_student_info(valid_homework): return False else: print("【警告】沒有有效提交的作業") # 寫入學生作業登記表 for student in students_info: if student['npuid'] in npuid_submit: student['submit'] += 1 write_students_info(students_info) print(f"【完成】有效提交作業人次 {valid_homework.__len__()}") return True # 主菜單 def menu(): print("") print("==============================") print("+ 作業登記器 - by huidong") print("============================== ") print("按任意鍵開始登記作業\n") getch() if register(): print("【恭喜】完成本次作業登記") else: print("【中止】放棄本次作業登記") ############## 主函數 ############## if __name__ == "__main__": while True: menu()