)
一、背景需求继续把园园通下载的幼儿数据合并、配学号、分班便于转入班级文件夹私发【办公类-112-06】20260228园园通信息合并配学号拆班园园通市级编号在excel中的位置调整调整最适合列宽https://mp.csdn.net/mp_blog/creation/editor/159155166二、复用代码00代码主要是把“大班一班”变成“大1班”01代码是匹配上学号拆分班级一素材准备把下载的一份所有幼儿园的信息xlsx放入“园园通下载” 2025082520250825_2025_学年出入所园儿童基本情况登记 表一空 01 1、下载园园通新生名册.xls,把两个新生名册合并在一起 2、部分插班生信息手动添加 deepseek阿夏 20260917 import pandas as pd import os import re date20260825 def merge_and_format_excel(): # 定义文件路径 path rD:\Python最终内容\20260902 2026园园通幼儿信息提取配学号拆班发班主任 # 设置路径 folder_path path r\00 园园通下载 output_path path r\02 园园通全部班级班信息合并.xlsx # 获取文件夹中的所有Excel文件 excel_files [f for f in os.listdir(folder_path) if f.endswith((.xlsx, .xls))] # if len(excel_files) 2: # print(234文件夹中Excel文件数量不足2个) # return # 读取所有Excel文件 dfs [] for file in excel_files[:3]: # 只处理前两个文件 file_path os.path.join(folder_path, file) df pd.read_excel(file_path) dfs.append(df) print(f已读取文件: {file}) # 合并数据 merged_df pd.concat(dfs, ignore_indexTrue) # 将列名ID改为市登记编号如果存在 if ID in merged_df.columns: merged_df.rename(columns{ID: 市登记编号}, inplaceTrue) print(已将列名ID改为市登记编号) else: print(未找到名为ID的列跳过重命名) # 格式化班级列统一改为托1班、小1班、中1班、大1班格式 def format_class_name(class_name): if pd.isna(class_name): return class_name class_str str(class_name) # 定义班级类型映射 class_type_map { 托: 托, 托大: 托, 小: 小, 中: 中, 大: 大 } # 中文数字到阿拉伯数字的映射 chinese_to_arabic { 一: 1, 二: 2, 三: 3, 四: 4, 五: 5, 六: 6, 七: 7, 八: 8, 九: 9, 十: 10, 十一: 11, 十二: 12 } # 先提取班级类型 class_type None class_num None # 匹配各种格式 # 1. 匹配托大X班、小X班、中X班、大X班格式 match re.search(r(托大|小|中|大)([一二三四五六七八九十\d])班, class_str) if match: class_type match.group(1) class_num match.group(2) else: # 2. 匹配大一班、托一班格式 match re.search(r(托|小|中|大)([一二三四五六七八九十])班, class_str) if match: class_type match.group(1) class_num match.group(2) else: # 3. 匹配大班一班格式 match re.search(r(托大|小|中|大)班([一二三四五六七八九十])班, class_str) if match: class_type match.group(1) class_num match.group(2) else: # 4. 匹配一班大班格式 match re.search(r([一二三四五六七八九十])班(托大|小|中|大)班, class_str) if match: class_num match.group(1) class_type match.group(2) else: # 5. 匹配只有班级类型没有班号的情况 match re.search(r(托大|小|中|大)班, class_str) if match: class_type match.group(1) class_num 1 # 默认班号为1 else: # 6. 匹配只有班级类型没有班字的情况 match re.search(r(托大|小|中|大), class_str) if match: class_type match.group(1) class_num 1 # 默认班号为1 if class_type: # 标准化班级类型 if class_type 托大: std_type 托 else: std_type class_type # 转换班号 if class_num: if class_num in chinese_to_arabic: num chinese_to_arabic[class_num] else: num class_num return f{std_type}{num}班 # 如果没有匹配到任何模式尝试直接提取数字 # 检查是否已经是托1班这样的格式 match re.match(r([托小中大])(\d)班, class_str) if match: return class_str # 已经是正确格式 # 最后尝试如果字符串中包含托、小、中、大且包含数字 for t in [托, 小, 中, 大]: if t in class_str: # 提取所有数字 nums re.findall(r\d, class_str) if nums: return f{t}{nums[0]}班 # 如果还是无法处理返回原值 print(f警告无法识别的班级格式 - {class_str}) return class_str # 查找包含班级信息的列 class_columns [col for col in merged_df.columns if any(keyword in col for keyword in [班, class, 班级])] if class_columns: for class_col in class_columns: print(f检测到班级列: {class_col}) merged_df[class_col] merged_df[class_col].apply(format_class_name) else: print(未检测到班级列跳过格式转换) # 保存合并后的文件 merged_df.to_excel(output_path, indexFalse) print(f文件已保存至: {output_path}) print(f合并完成共{len(merged_df)}条记录) # 显示一些样本数据以供验证 print(\n前10条数据的班级信息) if class_columns: for class_col in class_columns: print(f\n{class_col}列的前10个值) sample_values merged_df[class_col].head(10).tolist() for i, val in enumerate(sample_values, 1): print(f {i}. {val}) else: print(未找到班级列) # 显示所有列名 print(\n合并后的所有列名) print(merged_df.columns.tolist()) # 执行函数 if __name__ __main__: merge_and_format_excel()根据班级信息表里面的学号进行匹配学号做出所有的孩子在一起的表然后拆分成单独班级表。 20250825_2025_学年出入所园儿童基本情况登记 表一空 01 1、用合并xls与班级信息表的学号匹配按学号排队 2、按班级拆分成一个个班级最适合列宽一行非自动换行 3、按指定的列名顺序重新排列列的位置 20260317 import pandas as pd import os from openpyxl.utils import get_column_letter from openpyxl.styles import Alignment from openpyxl.styles import numbers # 设置路径 path rD:\Python最终内容\20260902 2026园园通幼儿信息提取配学号拆班发班主任 date20260825 # 定义目标列名顺序 target_columns [ 学号, 班级, 姓名, 市登记编号, 性别,出生地, 证件类型, 证件号码, 姓名拼音, 曾用名/英文名, 出生日期, 年级, 班级名称, 入园日期, 就读方式, 国籍/地区, 健康状况, 血型, 户口性质, 非农业户口类型, 港澳台侨外, 民族, 出生地-省份, 籍贯-省份, 是否人户一致, 户口所在地-省份, 户口所在地-城市, 户口所在地-区县, 户口所在地-街道, 户口所在地-居委, 户口所在地-详细地址, 现居地-省份, 现居地-城市, 现居地-区县, 现居地-街道, 现居地-居委, 现居地邮政编码, 现居地-详细地址, 监护人姓名, 监护人证件类型, 监护人证件号, 监护人手机, 与幼儿关系, 是否监护人, 是否是第一监护人, 是否是军烈子女, 是否是优抚子女, 是否是进城务工人员随迁子女, 是否是部队子女, 是否是孤儿, 是否是残疾幼儿, 残疾幼儿类别, 更新时间, 机构所在地区, 机构ID, 机构名称, 办园点ID, 办园点编码, 办园点名称, 班级昵称, 出生地-区县, 机构编码, 籍贯-区县, 籍贯-城市, 幼儿ID, 创建时间, 班级ID, 版本号, 幼儿特长, 户口所在地-居委-其他, 现居地-街道-其他, 户口所在地-街道-其他, 现居地-居委-其他, 特异体质, 出生地-城市, 原幼儿编号, 班级排序 ] def calculate_display_width(text): 计算字符串在Excel中的显示宽度 中文字符占2个单位英文字符和数字占1个单位 if text is None or pd.isna(text): return 0 text str(text) width 0 for char in text: # 判断是否为中文字符包括中文标点 if \u4e00 char \u9fff or char in 。“”‘’【】《》: width 2 else: width 1 return width def reorder_columns(df, target_columns): 按照目标列名顺序重新排列DataFrame的列 # 获取DataFrame中实际存在的列 existing_columns [] missing_columns [] for col in target_columns: if col in df.columns: existing_columns.append(col) else: missing_columns.append(col) # 获取目标列中不存在的其他列放在最后 other_columns [col for col in df.columns if col not in existing_columns] if missing_columns: print(f警告以下目标列在数据中不存在将被忽略{missing_columns}) if other_columns: print(f注意以下额外列将放在最后{other_columns}) # 重新排列列顺序 return df[existing_columns other_columns] # 1. 读取园园通信息表将所有列作为字符串读取保持原始格式 df_main pd.read_excel(path r\02 园园通全部班级班信息合并.xlsx, dtypestr) # 2. 读取班级信息表的所有工作表将所有列作为字符串读取 xls pd.ExcelFile(path r\01 20260805班级信息表.xlsx) sheet_names xls.sheet_names # 3. 合并所有班级信息表 df_list [] for sheet in sheet_names: df_sheet pd.read_excel(xls, sheet_namesheet, dtypestr) # 所有列作为字符串读取 df_sheet[班级] sheet # 添加班级列 df_list.append(df_sheet) df_info pd.concat(df_list, ignore_indexTrue) # 4. 匹配学号 df_merged pd.merge(df_main, df_info[[班级, 姓名, 学号]], left_on[班级名称, 姓名], right_on[班级, 姓名], howleft) # 5. 移动学号列到最前面这一步现在会被后面的重新排序列覆盖但保留以确保学号存在 cols df_merged.columns.tolist() cols [学号] [col for col in cols if col ! 学号] df_merged df_merged[cols] # 6. 对完整匹配结果进行排序并保存 # 学号列转换为数值类型用于排序但保存时保持原始文本格式 df_merged[学号_排序] pd.to_numeric(df_merged[学号], errorscoerce) # 先按班级排序托1班、托2班、小1班、小2班... # 创建班级排序的映射关系 class_order { 托1班: 1, 托2班: 2, 托3班: 3, 托4班: 4, 小1班: 11, 小2班: 12, 小3班: 13, 小4班: 14, 小5班: 15, 中1班: 21, 中2班: 22, 中3班: 23, 中4班: 24,中5班: 25,中6班: 26, 大1班: 31, 大2班: 32, 大3班: 33, 大4班: 34,大5班: 35 } # 添加临时排序列 df_merged[班级排序] df_merged[班级名称].map(class_order) # 先按班级排序再按学号排序 df_merged_sorted df_merged.sort_values(by[班级排序, 学号_排序]) # 删除临时排序列班级排序保留因为它在目标列中 df_merged_sorted df_merged_sorted.drop([学号_排序], axis1) # 按照目标列顺序重新排列 df_merged_sorted reorder_columns(df_merged_sorted, target_columns) # 保存排序后的完整表格并调整列宽 with pd.ExcelWriter(path r\03 匹配学号.xlsx, engineopenpyxl) as writer: df_merged_sorted.to_excel(writer, sheet_name匹配结果, indexFalse) # 获取工作表并调整列宽 worksheet writer.sheets[匹配结果] # 计算每列的最大显示宽度 for column in worksheet.columns: max_width 0 column_letter get_column_letter(column[0].column) # 获取列标题和所有单元格的最大显示宽度 for cell in column: try: # 计算单元格内容的显示宽度 cell_width calculate_display_width(cell.value) if cell_width max_width: max_width cell_width except: pass # 设置列宽添加一点额外空间 # Excel列宽单位是标准字符宽度中文字符需要额外空间 adjusted_width max_width 2 # 添加2个字符的边距 # 限制最小宽度为8最大宽度为100 worksheet.column_dimensions[column_letter].width min(max(adjusted_width, 8), 100) # 将所有单元格设置为文本格式 for row in worksheet.iter_rows(): for cell in row: cell.number_format # 设置文本格式 # 7. 按班级拆分并保存为单独工作簿 # 创建输出文件夹 output_folder path r\04 拆分班级 if not os.path.exists(output_folder): os.makedirs(output_folder) # 按班级拆分 for class_name in df_merged[班级名称].unique(): # 筛选当前班级的数据 class_df df_merged[df_merged[班级名称] class_name] # 创建临时排序列用于排序 class_df class_df.copy() # 避免警告 class_df[学号_排序] pd.to_numeric(class_df[学号], errorscoerce) # 对每个班级内的数据按学号排序 class_df_sorted class_df.sort_values(by学号_排序) # 删除临时排序列 class_df_sorted class_df_sorted.drop(学号_排序, axis1) # 按照目标列顺序重新排列 class_df_sorted reorder_columns(class_df_sorted, target_columns) # 创建文件名去除可能存在的非法字符 safe_class_name .join([c for c in class_name if c not in r\/:*?|]) output_path os.path.join(output_folder, f05_{date}_园园通幼儿全部信息_{safe_class_name}.xlsx) # 保存为单独的工作簿并调整列宽 with pd.ExcelWriter(output_path, engineopenpyxl) as writer: sheet_name f{class_name}园园通幼儿数据 # 工作表名称不能超过31个字符 if len(sheet_name) 31: sheet_name sheet_name[:31] class_df_sorted.to_excel(writer, sheet_namesheet_name, indexFalse) # 获取工作表并调整列宽 worksheet writer.sheets[sheet_name] # 计算每列的最大显示宽度 for column in worksheet.columns: max_width 0 column_letter get_column_letter(column[0].column) # 获取列标题和所有单元格的最大显示宽度 for cell in column: try: # 计算单元格内容的显示宽度 cell_width calculate_display_width(cell.value) if cell_width max_width: max_width cell_width except: pass # 设置列宽根据最长字符的实际显示宽度 adjusted_width max_width 2 # 添加2个字符的边距 # 限制最小宽度为8最大宽度为100 worksheet.column_dimensions[column_letter].width min(max(adjusted_width, 8), 100) # 设置所有单元格为文本格式 for row in worksheet.iter_rows(): for cell in row: cell.number_format # 设置所有单元格为文本格式 print(处理完成) print(f1. 已生成完整匹配表: 02匹配学号分园新生.xlsx已按班级和学号排序按指定列名顺序排列所有单元格保持文本格式根据实际显示宽度计算最适合列宽) print(f2. 已按班级拆分保存到 {output_folder} 文件夹每个班级内按学号排序按指定列名顺序排列所有单元格保持文本格式根据实际显示宽度计算最适合列宽)因为某些孩子还没有进园园通所以会缺少孩子的信息根据缺少那个学号就能看出缺人了。后续等孩子进园园通了再下载所有信息按两个代码重新匹配新的班级幼儿数据表。感悟写智慧课题时用AI总结经验其中就提到“复用代码”的策略本项目就是一个“复用代码”的项目完全套用去年的代码块实现各班幼儿数据的分班。这个Excel包含了所有的幼儿信息但是总体来看用到最多的还是“转学时的需要填写的市登记编号”所以我把它放在前面D列。