在Linux与MacOS系统下使用Python识别Excel单元格内局部删除线文本的可行方案
在Linux与MacOS系统下使用Python识别Excel单元格内局部删除线文本的可行方案
你遇到的问题其实是两个关键原因导致的:一是CellRichText的元素可能是普通无格式字符串或带格式的文本片段,你没有做类型判断就直接访问font属性;二是代码里的拼写错误——stike应该是strike。我来帮你解决这个问题,同时补充一些更全面的可行思路。
一、修正OpenPyXL代码解决当前报错
首先针对你现有的代码,我们修正类型判断逻辑和拼写错误,就能正常识别带删除线的富文本片段:
from openpyxl import load_workbook from openpyxl.cell.rich_text import CellRichText, TextBlock main_xlsx = "test_wb.xlsx" wb = load_workbook(main_xlsx, rich_text=True) ws = wb["Sheet1"] for i in range(1, ws.max_row + 1): my_cell = ws[f"C{i}"] # 用f-string简化单元格坐标拼接 if isinstance(my_cell.value, CellRichText): for part in my_cell.value: # 区分普通字符串和带格式的TextBlock片段 if isinstance(part, TextBlock): # 注意拼写修正:是strike不是stike! if part.font.strike: print(f"找到带删除线的文本:{part.text}") else: # 处理无格式的普通文本部分 print(f"无格式文本片段:{part}") else: print(f"单元格C{i}:无富文本内容")
代码关键说明:
- 类型判断优化:用
isinstance()代替type()是Python中更推荐的类型检查方式,能兼容继承场景。 - 区分文本片段类型:
CellRichText是混合序列,包含普通str(无格式)和TextBlock(带格式)两种元素,必须先判断类型再访问font属性。 - 拼写错误修正:你原代码里的
stike是拼写错误,正确的属性名是strike,这也是后续即使类型正确也会报错的隐藏问题。
二、报错根源解析
OpenPyXL的CellRichText设计是为了兼容单元格内的混合格式文本:
- 当单元格内某段文本没有设置任何字体格式时,会被存储为普通
str对象; - 只有设置了格式(如删除线、加粗、颜色)的文本片段,才会被封装为
TextBlock对象,这类对象才有font属性可以访问。
你的原始代码没有区分这两种元素,直接遍历所有元素并访问font,自然会触发str对象无font的AttributeError。
三、进阶方案:直接解析XLSX底层XML
如果OpenPyXL的富文本处理在某些复杂场景下有局限(比如极端格式的单元格),你可以直接操作XLSX的底层XML结构——因为XLSX本质是一个ZIP压缩包,内部包含多个描述内容和格式的XML文件:
实现思路:
- 将XLSX文件当作ZIP包解压,读取对应工作表的XML文件(如
xl/worksheets/sheet1.xml); - 遍历单元格的
<c>元素,找到包含<r>(文本运行片段)的富文本单元格; - 检查每个
<r>元素的<rPr>(运行属性)中是否包含<strike/>标签,来判断该片段是否有删除线。
示例代码:
import zipfile import xml.etree.ElementTree as ET # 定义XLSX XML的命名空间,必须指定才能正确解析 NS = { "ss": "http://schemas.openxmlformats.org/spreadsheetml/2006/main" } main_xlsx = "test_wb.xlsx" with zipfile.ZipFile(main_xlsx, "r") as zf: # 读取第一个工作表的XML文件,根据你的实际表名调整路径 with zf.open("xl/worksheets/sheet1.xml") as f: tree = ET.parse(f) root = tree.getroot() # 遍历所有单元格 for cell in root.findall(".//ss:c", NS): cell_ref = cell.attrib.get("r") # 获取单元格坐标(如C1) # 查找单元格内的所有文本运行片段 runs = cell.findall(".//ss:r", NS) if not runs: print(f"单元格{cell_ref}:无富文本内容") continue for run in runs: # 检查是否存在删除线属性 strike_tag = run.find(".//ss:strike", NS) # 提取该片段的文本内容 text_content = "".join([t.text for t in run.findall(".//ss:t", NS)]) if strike_tag is not None: print(f"单元格{cell_ref}中带删除线的文本:{text_content}") else: print(f"单元格{cell_ref}中无删除线的文本:{text_content}")
这种方法更底层,能处理所有XLSX支持的格式,但需要熟悉OOXML的结构,适合复杂场景的定制化需求。
四、关于xlrd v1.2的使用建议
你提到的xlrd v1.2确实支持读取XLSX,但该版本已经停止维护,且从xlrd v2.0开始完全移除了XLSX格式的支持,仅兼容旧版XLS文件。除非你必须维护非常老旧的代码环境,否则不推荐在新项目中使用这个版本。
备注:内容来源于stack exchange,提问作者Deficient_brain_words
相关产品推荐
相关产品推荐

