使用xlrd读取.xls文件单元格内各文本片段的字体颜色与删除线状态的实现问题
使用xlrd读取.xls文件单元格内各文本片段的字体颜色与删除线状态的实现问题
嘿,我懂你的困扰了——你现在用xlrd只能拿到整个单元格的统一格式,但单元格里的文本是分段设置了不同样式的(比如部分文字带删除线、部分是红色),这确实得用到xlrd的富文本(Rich Text)解析功能才能解决。
问题根源
你当前的代码是基于单元格整体的xf_index获取格式的,但.xls文件里的分段格式化文本是按「文本片段(run)」来存储的,每个片段有独立的字体配置。常规的单元格xf格式只对应单元格的默认样式,当单元格内有多个格式不同的文本时,必须解析单元格的富文本信息才能拿到每个片段的具体格式。
解决方案:解析单元格的富文本片段
xlrd其实支持读取单元格的富文本内容,每个单元格的rich_text属性会返回一个列表,列表里的每个元素是(文本内容, 字体索引)的元组:
文本内容:当前片段的具体文字字体索引:该片段对应的字体配置索引,通过它可以从workbook.font_list里拿到对应的字体样式(颜色、删除线等)
下面是修改后的核心代码,我替换了你原来处理单个单元格的逻辑,加入了富文本解析的部分:
修改后的完整代码示例
import pandas as pd import numpy as np import xlrd import math # 假设你的get_color_palette和compare_font_color方法已实现 palette = self.get_color_palette(data_path) workbook = xlrd.open_workbook(data_path, formatting_info=True, on_demand=True) dfs = {} for sheet_name in sheet_names: print(f'Read sheet: {sheet_name}') sheet = workbook.sheet_by_name(sheet_name) filtered_data = [] for row in range(sheet.nrows): filtered_row = [] for col in range(sheet.ncols): cell = sheet.cell(row, col) # 处理空单元格 if cell.value == '': filtered_row.append(math.nan) continue # 检查单元格是否包含富文本(分段格式化内容) if hasattr(cell, 'rich_text') and cell.rich_text: # 存储每个文本片段的详细格式信息 cell_segment_details = [] for text_segment, font_idx in cell.rich_text: font = workbook.font_list[font_idx] # 判断是否带删除线(和你原逻辑保持一致) is_striked = not font.struck_out # 判断颜色是否符合你的要求 color_valid = self.compare_font_color(palette[font.colour_index]) # 保存片段的文本和格式信息 cell_segment_details.append({ 'text': text_segment, 'is_striked': is_striked, 'color_valid': color_valid }) # 按需组合片段信息,这里示例为带格式标记的字符串 formatted_cell = "" for seg in cell_segment_details: seg_text = seg['text'] # 给删除线片段加标记 if seg['is_striked']: seg_text = f"<strike>{seg_text}</strike>" # 给符合颜色要求的片段加标记(这里用[red]示例,可按需修改) if seg['color_valid']: seg_text = f"[red]{seg_text}[/red]" formatted_cell += seg_text filtered_row.append(formatted_cell) else: # 无富文本的单元格,沿用你原来的逻辑处理 xf_index = cell.xf_index xf = workbook.xf_list[xf_index] font_index = xf.font_index font = workbook.font_list[font_index] strike_bool = not font.struck_out font_color_bool = self.compare_font_color(palette[font.colour_index]) keep_cell = font_color_bool and strike_bool # 处理单元格值的类型 if isinstance(cell.value, (int, float)): if isinstance(cell.value, float) and cell.value.is_integer(): filtered_row.append(int(cell.value) if keep_cell else None) else: filtered_row.append(float(cell.value) if keep_cell else None) else: filtered_row.append(str(cell.value) if keep_cell else None) filtered_data.append(filtered_row) df_proper = pd.DataFrame(filtered_data) dfs[sheet_name] = df_proper workbook.unload_sheet(sheet_name)
关键细节说明
- 富文本判断:通过
hasattr(cell, 'rich_text') and cell.rich_text检查单元格是否包含分段格式化的文本,避免报错。 - 遍历文本片段:每个富文本片段对应独立的字体配置,通过字体索引可以精准获取该片段的删除线状态和颜色信息。
- 结果存储灵活:你可以根据需求把片段信息组合成带格式标记的字符串(比如示例中的
<strike>和[red]),或者直接存储为字典列表,方便后续Pandas的进一步处理。 - 兼容普通单元格:对于没有分段格式的单元格,依然沿用你原来的逻辑,保证代码的兼容性。
针对你给出的示例:
单元格内容:That can be
nota value
- "That"是红色(假设你的
compare_font_color识别红色为符合条件)- "not"是删除线
修改后的代码会把这个单元格处理成[red]That[/red] can be <strike>not</strike> a value的字符串,完美识别每个片段的格式状态。
备注:内容来源于stack exchange,提问作者Marcel D
相关产品推荐
相关产品推荐

