Excel读取标题头映射失败问题‘\uFEFF‘ 65279

本文探讨了在读取CSV文件时遇到的第一个列名映射失败问题,详细分析了问题产生的原因在于Excel分表操作中引入了不可见字符'uFEFF',并解释了该字符如何影响数据读取一致性。

Excel读取标题头映射失败问题

读取csv表格列名的时候第一个列名对应不上,

debug发现第一个字串头部多出’\uFEFF’ 65279字符导致hash地址不一致,无法对应。

校对出表过程发现是在excel制作时进行了分表操作。

但是csv文件不支持多表格存储,分表粘贴的过程中多出了’\uFEFF’ 65279分割符导致的问题。

import os import pandas as pd import re from pathlib import Path from openpyxl import load_workbook import warnings from collections import defaultdict import contextlib # ===== 配置参数 ===== CSV_DIR = r"F:\000-py\000比赛\html_test\data_clean" EXCEL_FILE = "rank_data_2.xlsx" SHEET_MAPPING = { "*成交*.csv": "成交查询", "*资金*.csv": "资金查询", "*持仓*.csv": "持仓查询" } CHUNK_SIZE = 50000 CONVERT_THRESHOLD = 0.8 # =================== def strip_whitespace(df): """高效去除单元格前后空白字符""" str_cols = df.select_dtypes(include=['object', 'string']).columns for col in str_cols: df[col] = df[col].str.strip() return df def text_to_number(df): """智能文本转数字(带阈值控制)""" for col in df.columns: if pd.api.types.is_numeric_dtype(df[col]): continue converted = pd.to_numeric(df[col], errors='coerce') valid_ratio = converted.notna().mean() if valid_ratio > CONVERT_THRESHOLD: df[col] = converted return df def match_sheet_name(csv_path): """根据映射规则匹配Sheet名""" filename = Path(csv_path).name for pattern, sheet_name in SHEET_MAPPING.items(): # 修复正则表达式转义问题 regex_pattern = re.escape(pattern).replace(r'\*', '.*') if re.fullmatch(regex_pattern, filename): return sheet_name return None def safe_excel_writer(excel_file): """创建安全的Excel写入器,避免属性设置错误""" # 确保目标Excel存在 excel_path = Path(excel_file) if not excel_path.exists(): # 创建一个临时Excel文件,包含一个工作表 with pd.ExcelWriter(excel_file, engine='openpyxl') as temp_writer: pd.DataFrame().to_excel(temp_writer, index=False, sheet_name="Temp") # 创建ExcelWriter对象(追加模式) return pd.ExcelWriter( excel_file, engine="openpyxl", mode="a", if_sheet_exists="overlay" ) # ==== 主处理流程 ==== if __name__ == '__main__': csv_files = list(Path(CSV_DIR).glob("*.csv")) # 分组处理:按工作表名分组CSV文件 sheet_groups = defaultdict(list) for csv_path in csv_files: sheet_name = match_sheet_name(csv_path) if sheet_name: sheet_groups[sheet_name].append(csv_path) else: print(f"跳过: {csv_path.name} - 无匹配Sheet配置") # 初始化Excel写入器 writer = safe_excel_writer(EXCEL_FILE) # 使用上下文管理器处理工作簿 with writer as writer: # 在追加模式下,writer.book已经被加载 # 确保至少有一个可见的工作表 visible_sheets = [ws for ws in writer.book.worksheets if ws.sheet_state == "visible"] if not visible_sheets and writer.book.worksheets: # 将第一个工作表设为可见 writer.book.active = 0 # 激活第一个工作表 writer.book.active.sheet_state = "visible" print(f"警告: 已激活首个工作表 {writer.book.active.title}") # 处理每个工作表组 for sheet_name, file_list in sheet_groups.items(): print(f"\n处理工作表: {sheet_name}") print(f"包含CSV文件数: {len(file_list)}") # 检查工作表是否存在,存在则创建 if sheet_name in writer.book.sheetnames: sheet = writer.book[sheet_name] # 清空工作表内容 if sheet.max_row > 0: sheet.delete_rows(1, sheet.max_row) start_row = 0 print(f"清空现有工作表: {sheet_name}") else: sheet = writer.book.create_sheet(sheet_name) start_row = 0 print(f"创建新工作表: {sheet_name}") # 处理该工作表的每个CSV文件 for file_idx, csv_path in enumerate(file_list): print(f"处理文件: {csv_path.name} ({file_idx+1}/{len(file_list)})") # 分块处理大CSV文件 for i, chunk in enumerate(pd.read_csv(csv_path, chunksize=CHUNK_SIZE, encoding='utf-8-sig')): # 预处理 chunk = strip_whitespace(chunk) chunk = text_to_number(chunk) # 确定是否写入表头(每个文件的第一块写入表头) write_header = (i == 0) and (file_idx == 0) # 注意:每个工作表只写一次表头,且是第一个文件的第一个块 # 但实际上,我们清空了工作表,所以每个工作表只写一次表头。但是,我们可能写入多个文件,所以第一个文件的第一个块写入表头,后续文件都表头。 # 但是,我们是在同一个工作表内连续写入多个文件,所以后续的文件应该再写表头。 # 因此,我们修改:只有该工作表的第一个文件的第一块写入表头。 # 但是,由于我们在处理工作表时,每个工作表只清空一次,所以每个工作表写入一次表头(即第一个文件的第一个块)即可。 # 所以,上面的条件应该是:当前文件是第一个文件(file_idx==0)且当前块是第一个块(i==0) # 注意:如果工作表是新建的,那么第一个文件的第一块需要写表头;如果是已有的工作表,我们清空了,那么第一个文件的第一块也要写表头。 # 所以条件变。 # 将块写入Excel chunk.to_excel( writer, sheet_name=sheet_name, index=False, header=write_header, startrow=start_row ) # 更新起始行位置 if write_header: start_row += len(chunk) + 1 # 包括标题行 else: start_row += len(chunk) print(f" - 已写入块 #{i+1} (行数: {len(chunk)}), 当前起始行: {start_row}") print(f"\n处理完成! 更新文件: {EXCEL_FILE}") print("验证建议: 检查数据列对齐、特殊字符保留和空值处理") 改进上述代码要求解决Python UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xb1 in position 0: invalid start byte错误
09-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值