【QT】使用Qxlsx读取Excel单元格中函数表达式的结果值
【QT】使用Qxlsx读取Excel单元格中函数表达式的结果值
零、起因
是这样的,目前朋友托我写一款模板生成软件,任务是先把他写的程序文件复制一份出来,然后再根据Excel中对应位置的单元格的值,修改程序文件副本中的某些文件。对于读Excel的需求,经过测试,最终选择Qxlsx这款开源QT组件来读取Excel中的值,但是Excel中有些单元格用的是Excel函数,使用Document::read函数读出来的是Excel函数表达式,而不是Excel函数表达式函数的结果。故开启本文……
壹、调查
网络调查
通过询问AI、搜索等方式,尝试寻求使用Qxlsx读取Excel单元格中函数表达式结果值的方法,可惜的是我没有找到相应的方法。

不过在与AI对话的过程中,我得到了一个重要的线索:

在AI列举的这些库中,大多都是不支持Excel函数表达式值的读取的,想一想也正常,毕竟写一套解析引擎代码比写一套读取内容代码复杂多了,后面是想参考一下其他能读Excel函数表达式值的库的做法,问下来发现openpyxl支持读Excel函数表达式值,而且原理这里也提到了,是因为Excel文件中的函数表达式的结果值会被保存在单元格中,而openpyxl并不是经过计算得出的,而是直接读出保存在单元格中的结果值的。而且从最后一句话中,我们应该能得出这样的结论:Excel文件保存了什么就只能读出什么,没有保存的是读不出的。
既然得到这样的线索,而且我们也能拿到Qxlsx的源码,那在读取阶段只需要读一下结果值存在Cell对象中不就可以了?
XLSX文件结构调查
众所周知,.xlsx文件本质上是一个压缩包,于是我先创建了一个包含有函数表达式的Excel文件并保存为excel.xlsx。

把excel.xlsx文件使用7z解压,得到如下目录结构:
Microsoft Windows [版本 10.0.22631.4460]
(c) Microsoft Corporation。保留所有权利。
D:\y17mm\Desktop\xlsx文件分析>tree /f
卷 井中月 的文件夹 PATH 列表
卷序列号为 FE8F-1AB3
D:.
│ excel.xlsx
│
└─excel
│ [Content_Types].xml
│
├─docProps
│ app.xml
│ core.xml
│ custom.xml
│
├─xl
│ │ sharedStrings.xml
│ │ styles.xml
│ │ workbook.xml
│ │
│ ├─theme
│ │ theme1.xml
│ │
│ ├─worksheets
│ │ sheet1.xml
│ │
│ └─_rels
│ workbook.xml.rels
│
└─_rels
.rels
D:\y17mm\Desktop\xlsx文件分析>
简单观察文件后发现,表格文件里Sheet1的数据就存在excel/xl/worksheets/sheet1.xml中,汉字不存具体的值(但这个不需要我们关心,是从excel/xl/sharedStrings.xml中映射过来的),使用标签v与其他xml文档做映射,而函数表达式会存下来,标签是f,省略了等于号,函数表达式的值也会存下来,就与公式在同一个c标签中,用与保存其他文字相同的标签v来保存……
excel/xl/worksheets/sheet1.xml的内容:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet
xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:etc="http://www.wps.cn/officeDocument/2017/etCustomData">
<sheetPr/>
<dimension ref="A1:B2"/>
<sheetViews>
<sheetView tabSelected="1" workbookViewId="0">
<selection activeCell="B2" sqref="B2"/>
</sheetView>
</sheetViews>
<sheetFormatPr defaultColWidth="8.88888888888889" defaultRowHeight="14.4" outlineLevelRow="1" outlineLevelCol="1"/>
<cols>
<col min="1" max="1" width="9.11111111111111" customWidth="1"/>
</cols>
<sheetData>
<row r="1" spans="1:2">
<c r="A1" t="s">
<v>0</v>
</c>
<c r="B1" t="s">
<v>1</v>
</c>
</row>
<row r="2" spans="1:2">
<c r="A2" s="1" t="s">
<v>2</v>
</c>
<c r="B2" t="str">
<f>LEFT(B1,1)</f>
<v>钟</v>
</c>
</row>
</sheetData>
<pageMargins left="0.75" right="0.75" top="1" bottom="1" header="0.5" footer="0.5"/>
<headerFooter/>
</worksheet>
excel/xl/sharedStrings.xml的内容:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst
xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="3" uniqueCount="3">
<si>
<t>名字</t>
</si>
<si>
<t>钟离</t>
</si>
<si>
<t>姓氏</t>
</si>
</sst>
真的有保存函数表达式的结果值,那Qxlsx实现读取Excel单元格中函数表达式的结果值就具有了可行性!
源码追踪调查
按理说Qxlsx的Document::read函数读出来的应该就是c标签中v标签的内容呀,可为啥读到的是c标签中f标签呢?

通过跟踪Qxlsx的读取单元格值的源码,不难发现这样一个函数:

发现在读取值时会先判断是否有公式,如果有,则返回等于号加公式文本,否则不是公式也不是日期时间,则使用cell->value()返回cell中的值。到这里,应该能想到解决方案了,我们只需要调用这个cellAt函数,并且不需要管是否有函数公式,直接调用返回value()的结果就好了。
贰、解决
基于以上结论,不难写出这样一个函数用于读取Excel中单元格函数表达式的结果值:
#include "xlsxdocument.h"
#include "xlsxcellformula.h"
#include "xlsxcell.h"
#include <QDebug>
bool isDebug = true;
QVariant readCellValue(QXlsx::Document& xlsx, const int& row, const int& col, const bool readVal=true){
if(readVal) {
auto* ws = xlsx.currentWorksheet();
auto *cell = ws->cellAt(row, col);
if(cell != nullptr && cell->hasFormula()) { // 存在公式
if(isDebug) qDebug()<<"公式";
if(isDebug) qDebug()<<"cell->formula().isValid()"<<cell->formula().isValid();
if(isDebug) qDebug()<<"cell->formula().formulaText()"<<cell->formula().formulaText();
if(isDebug) qDebug()<<"cell->formula().formulaType()"<<cell->formula().formulaType();
if(isDebug) qDebug()<<"cell->value()"<<cell->value();
QVariant v = cell->value();
QVariant emptyVariant;
if(v.toString().compare(emptyVariant.toString()) == 0) { // 如果值为空
return "=" + cell->formula().formulaText(); // 返回公式
} else {
return cell->value(); // 返回计算值
}
}
}
// cell->d_func()->value
return xlsx.read(row, col);
}
要读取值时判断是否存在函数表达式,如果存在,则尝试获取函数表达式的值,如果函数表达式有有效值则返回值,否则按照默认方式返回函数表达式。
经过调整,我们成功地拿到了Excel单元格中函数表达式的结果值:

叁、总结
Excel表格单元格中函数表达式的结果值一般会存在表格文件中的,理论上只要能读取xlsx表格的单元格的值的代码经过稍加改造都可以读到Excel单元格中函数表达式的结果值。本次Qxlsx读取Excel单元格中函数表达式的结果值代码总结如下:
int row = 2; // 行
int col = 2; // 列
QString xlsxFile = "D:\\y17mm\\Desktop\\xlsx文件分析\\excel.xlsx"; // 文件路径
QXlsx::Document xlsx(xlsxFile);
auto* ws = xlsx.currentWorksheet();
auto *cell = ws->cellAt(row, col);
auto ret = cell->value();
qDebug()<<"读取结果:"<<ret;
肆、参考资料
- Qxslx https://github.com/dbzhang800/QtXlsxWriter
- AI对话内容 https://yiyan.baidu.com/share/0zdNk8Z7VN?utm_invite_code=A66Y52pyQAd0FFd681/Jqw==&utm_name=5bCP6bG85pWP5ZOy&utm_fission_type=common
【QT】使用Qxlsx读取Excel单元格中函数表达式的结果值的更多相关文章
- C# 开源组件--NPOI读取Excel单元格中的公式值
今天在项目中碰到了EXCEL导入的数据是用公式生成,直接导入不了数据,写在博客中方便自已查询也可以给想找这方面的参考一下: 用NPOI导入时,在OFFICE 2007中的文件导入时一般会用XSSF,所 ...
- 如何在excel单元格中插入图片批注
在excel单元格中插入图片批注的方法: 1.选定要插入图片的单元格,然后右键选择插入批注. 2.然后会插入一个批注框,为了不影响图片效果,可以将批注文字都删除.然后鼠标移动到批注框边角再右键. 3. ...
- poi 升级至4.x 的问题总结(POI Excel 单元格内容类型判断并取值)
POI Excel 单元格内容类型判断并取值 以前用 cell.getCachedFormulaResultType() 得到 type 升级到4后获取不到了 换为:cell.getCellType( ...
- C# ASP.NET 读取EXCEL 单元格 读取 空值 不显示
跟大家分享一下,[摘自]:http://blog.csdn.net/li185416672/article/details/8213729 读取excel时,某些单元格为空值 原来如此: 当我们用ol ...
- excel单元格中批量加入固定字符
excel单元格前怎么批量加字母 现在我要在联系人这列,每个姓名前加入衡阳的首字母简写(HY). 3 在同行上面随便找列,我找D列.输入公式:="HY"&A2. 5 输入后 ...
- 通过VBA,当在EXCEL单元格中输入任意的日期格式时,都能自动转换为指定的标准格式的日期值
在日常录入EXCEL表格的单元格里 ,我们输入一些一般性的日期内容,如:2017-10-17 或 2017/10/17时,EXCEL会自动识别为日期并按单元格设计格式显示,单元格中存储的值也是日期格式 ...
- POI如何自动调整Excel单元格中字体的大小
问题 目的是要将Excel中的文字全部显示出来,可以设置对齐格式为[缩小字体填充],但是这样的话只能展示出一行数据,字体会变得很小.还有一种办法,设置对齐格式为[自动换行],然后让单元格中的字体自动调 ...
- Java 在Excel单元格中应用一种/多种字体样式
在Excel表格中,设置单元格字体样式时,可以对单元格内的所有字符应用同一样式,即获取指定单元,应用样式即可:另外也可以对单元格内的不同字符内容应用不同字体样式,即获取单元格中的字符位置,应用样式:本 ...
- C#/VB.NET 在Excel单元格中应用多种字体格式
在Excel中,可对单元格中的字符串设置多种不同样式,通常只需要获取到单元格直接设置样式即可,该方法设置的样式会应用于该单元格中的所有字符.如果需要对单元格中某些字符设置样式,则可以参考本文中的方法. ...
- 在excel单元格中提取信息
平时在excel中处理数据的时候,肯定会遇到在单元格提取信息的情况,比如在地址中提取省.市.地区等,如果数据源内容规整的话,可以直接使用left().right().mid()等函数直接提取,但是大多 ...
随机推荐
- 关于前端上传excell时间的问题
当前端导入excell里的数据时,只能获取到下面类似的这种数据 Excel存储的日期是从1900年1月1日开始按天数来计算的,也就是说1900年1月1日在Excel中是1. 转化的思路和对Excel中 ...
- CDS标准视图:一次性账户的客户行项目 I_ONETIMEACCOUNTCUSTOMER
视图名称:一次性账户的客户行项目 视图类型:基础 视图代码: 点击查看代码 @EndUserText.label: 'One-Time Account Data for Customer Items' ...
- 安装Docker及相关容器
一,Docker简介百科说:Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱 ...
- w3cschool-memcached教程
https://www.w3cschool.cn/memcached/ Memcached 教程 Memcached是一个自由开源的,高性能,分布式内存对象缓存系统. 手册简介 Memcached ...
- RSA 小规模演算
原理 秘钥生成 加解密 解密验证 小规模演算
- 天翼云VPC支持专线健康检查介绍
本文分享自天翼云开发者社区<天翼云VPC支持专线健康检查介绍>,作者:汪****波 天翼云支持本地数据中心IDC(Internet Data Center)通过冗余专线连接到天翼云云上专有 ...
- VSCode Romote SSH连接远程主机经常初始化?10个解决方法!!
解决方法: 删除远程主机上的 .vscode-server 文件夹:这个文件夹包含 VSCode 的远程服务器组件.如果这个文件夹损坏或配置不正确,会导致连接问题.删除并重新安装可以确保服务器组件是干 ...
- [HAOI2018] 染色 题解
第一眼肯定想到容斥.设 \(G(k)\) 表示至少有 \(k\) 种颜色符合要求,\(F(k)\) 表示恰好有 \(k\) 种颜色符合要求.显然 \(k\) 的上界 \(t=\min(m,\lfloo ...
- startup_stm32f10x_xx.s 启动代码文件的选择
网上查到的各个文件的解释是: startup_stm32f10x_cl.s 互联型的器件startup_stm32f10x_hd.s 大容量startup_stm32f10x_hd_vl.s 大容量s ...
- nginx: [error] open() “/usr/local/var/run/nginx.pid” failed (2: No such file or directory)