千灵

Back

1. 问题#

使用 Excel 保存 CSV 文件时,长度大于 11 位的数字会被强制以科学计数法形式储存,导致数据丢失精度,例如 Unix 时间戳1532793600000变为1.53279E+12,导致时间由2018-07-29 00:00:00变为2018-07-28 23:00:00

2. 解决方法#

此问题为 Excel 软件设计缺陷,将单元格格式改为文本亦无法解决,只能将数据内容本身改为文本格式来避免转换,如在前缀或后缀处增加占位符,下面是笔者编写的通过添加制表符尾缀实现此功能的程序。

3. 长数字转文本宏#

3.1 使用#

在 Excel 待处理 csv 文件内按下 Alt+F11 打开「Microsoft Visual Basic for Applications」,在左侧工程窗口空白处按下鼠标右键,选择「插入(N)」-「模块(M)」,随后在编辑区域内粘贴代码,按下 F5 运行即可给所有长度大于 11 位的列的数字末尾添加制表符。

使用数据时如何移除制表符:

  1. 如果应用于数据库,在导入时勾选类似「去除字符串两端的空白字符(如空格、制表符、换行符等)」的选项,如 SQLite 勾选 「Trim fields」,即可去除本程序增加的制表符还原为数字;
  2. 若应用于其他场景或数据库不支持自动去除制表符,可使用文本编辑器查找制表符替换为空白。

3.2 代码#

3.3 逻辑#

  1. 初始化变量:创建变量以存储工作表、最后一行和最后一列的位置、单元格值和数据数组;
  2. 获取活动工作表:设置操作对象 ws 为当前活动工作表;
  3. 确定数据范围:计算最后一行和最后一列的位置,以确保只处理包含数据的部分;
  4. 读取数据:将工作表中指定范围的数据读取到二维数组 data 中,以提高处理速度;
  5. 创建新数据数组:定义 newData 数组以存放处理后的数据,维度与 data 相同;
  6. 遍历单元格:使用两个嵌套循环遍历每个单元格,外层循环遍历行,内层循环遍历列;
  7. 检查数字长度:判断每个单元格的值是否为数字且长度是否大于 11;
  8. 添加制表符:如果条件满足,将该单元格的值末尾添加制表符 vbTab,否则保留原始值;
  9. 写回数据:将修改后的 newData 数组写回到工作表,更新所有单元格的值。

3.4 性能问题#

单元格数量:243789

处理时长:2.19s

为避免遗漏,本程序采取逐个单元格遍历判断长度决定是否修改的方法,性能不佳。以下是改为通过读取每列最后一行的值来判断列数据长度的程序,处理时长缩短至 1.14s,性能提升近一倍,仅适用于列数据长度统一的情况。

参考资料:

  1. 导出csv文件数字变科学计数法的解决方法
解决Excel保存CSV时长数字丢失精度的问题
https://qianling.pw/solve-excel-save-csv-long-number-loss-precision-issue/
Author 千灵
Published at August 1, 2024
Comment seems to stuck. Try to refresh?✨