You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Openpyxl读取的cell.value转换为匹配cell.number_format的格式化字符串

通用实现方案

Openpyxl默认返回的cell.value是单元格存储的原始值,不会自动按照cell.number_format渲染成Excel里的显示文本,我们可以通过格式规则映射、结合值类型判断做通用转换,覆盖绝大多数常规格式场景,输出和Excel端一致的显示结果。

可直接复用的实现代码如下:

import openpyxl
from datetime import datetime, date
import re
import sys

def excel_format_to_python_fmt(num_format):
    """
    将Excel number_format规则转换为Python可用的格式化串
    返回:(python格式化串, 是否为日期类型格式)
    """
    # Excel内置日期格式映射,可根据业务场景补充
    builtin_date_fmts = {
        14: "m/d/yyyy",
        15: "d-mmm-yy",
        16: "d-mmm",
        17: "mmm-yy",
        18: "h:mm AM/PM",
        19: "h:mm:ss AM/PM",
        20: "h:mm",
        21: "h:mm:ss",
        22: "m/d/yyyy h:mm",
    }
    is_date_fmt = False

    # 处理内置数字格式编码
    if isinstance(num_format, int):
        if num_format in builtin_date_fmts:
            num_format = builtin_date_fmts[num_format]
            is_date_fmt = True
    else:
        # 识别自定义日期格式:包含年月日时分秒、AM/PM占位符即判定为日期格式
        date_placeholder = re.compile(r'[ymdhsAM/PM]', re.IGNORECASE)
        if date_placeholder.search(num_format) and num_format != "0.00E+00":
            is_date_fmt = True

    if is_date_fmt:
        # 适配跨平台的无前导零格式符
        no_lead_fmt = "%-m" if not sys.platform.startswith("win") else "%#m"
        no_lead_day = "%-d" if not sys.platform.startswith("win") else "%#d"
        no_lead_hour = "%-H" if not sys.platform.startswith("win") else "%#H"
        # Excel日期占位符转Python strftime占位符,按长度从长到短替换避免误匹配
        fmt_map = {
            "yyyy": "%Y", "yy": "%y",
            "dddd": "%A", "ddd": "%a",
            "mmmm": "%B", "mmm": "%b",
            "dd": "%d", "d": no_lead_day,
            "mm": "%m", "m": no_lead_fmt,
            "hh": "%H", "h": no_lead_hour,
            "ss": "%S",
            "AM/PM": "%p", "am/pm": "%p"
        }
        py_fmt = num_format
        for old in sorted(fmt_map.keys(), key=lambda x: -len(x)):
            py_fmt = py_fmt.replace(old, fmt_map[old])
        return py_fmt, True
    else:
        # 清理数字格式里的Excel专用转义字符
        py_fmt = re.sub(r'_.', '', num_format)
        py_fmt = py_fmt.replace("\\", "")
        return py_fmt, False

def get_cell_display_text(cell):
    """获取和Excel端显示完全一致的单元格文本"""
    raw_val = cell.value
    if raw_val is None:
        return ""
    num_fmt = cell.number_format
    # 通用格式直接转字符串返回
    if num_fmt == "General":
        return str(raw_val)
    
    py_fmt, is_date = excel_format_to_python_fmt(num_fmt)
    if is_date and isinstance(raw_val, (datetime, date)):
        return raw_val.strftime(py_fmt)
    elif isinstance(raw_val, (int, float)):
        # 处理千分位、小数位数字格式
        if "#,##0" in py_fmt:
            dec_bit = 0
            if "." in py_fmt:
                dec_part = py_fmt.split(".")[-1]
                dec_bit = dec_part.count("0")
            return f"{raw_val:,.{dec_bit}f}"
        # 百分比、货币等格式可在此处补充对应转换逻辑
        return str(raw_val)
    else:
        return str(raw_val)

# 测试调用
if __name__ == "__main__":
    path = r'Test.xlsx'
    wb = openpyxl.load_workbook(path)
    sheet = wb.active
    target_cell = sheet.cell(row=2, column=3)
    print("原始值:", target_cell.value)
    print("单元格格式:", target_cell.number_format)
    print("Excel显示值:", get_cell_display_text(target_cell))

针对你提到的日期场景:当单元格number_format为[$-en-US]dddd, mmmm dd, yyyy、原始值为2022-01-31 00:00:00时,上述代码会返回Monday, January 31, 2022,和Excel显示效果完全一致。

使用时可根据业务中常用的自定义格式,补充格式映射规则即可:

  • 带条件判断的分段格式、特殊货币/百分比格式,可在格式转换函数中增加分支解析
  • 遇到匹配不准的格式,打印对应单元格的number_format实际值,补充到映射表即可快速适配
  • 代码已经兼容Windows、macOS/Linux系统下日期无前导零的格式差异

内容的提问来源于stack exchange,提问作者Finntech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:54:21