xlsm转存制表符分隔的txt文件(仿WPS逻辑)
# 原由
运营的同事需要将xlsm的表格另存为制表符分隔的txt文件,实际上也就是TSV文件。一般她们是WPS手动另存的,但是据反馈偶尔会出现另存的txt不能用的情况(未知详情),需要部门帮忙处理。我处理过几回,基本我这边手动另存是可以的,估计又是特殊字符串在windows的GBK编码下出的怪问题。不过,这不重要,重要的是手动处理显然不能满足我一个懒汉,而这种简单而又重复的任务显然很适合用脚本来处理。于是乎才有了这次的干货(大约)。
过程
首先是要用什么库来处理?
这个稍加百度、以及比对了一下,也似乎就openpyxl可以读xlsm了。
搞懂wps的逻辑转换逻辑
这个卡了一两天,后来总结出来几点:
- 制表符为分隔符;
- 有特殊符号(换行符
\n
和逗号,
)的字段要加双引号"
包裹住字段 - 双引号包裹的字段内若有双引号,要用双引号转义,如:
"Hello, World!"
最终将保存为"""Hello, World!"""
- 数字的处理:
- 数字达到一定长度会转变成科学计数(精度5),这个长度可能是11位(未实验验证,至少测试用的表格例子是完全符合预期)
- 会根据单元格的数字格式来保存数字,默认
General
保留小数点后2位,其他还有诸如0
保留整数、0.00
保留小数点后2位(即使整数也会,如:3
将保存成3.00
),可能还有更复杂的处理,这里没细研究,够用即可,不够再改
还有未解决的点
用某份文件对比生成的txt文件和手动保存的txt文件,发现其他表都是完全一致,只有某张表手动的表会在某末尾多了一个制表符,这个逻辑百思不得解,最终考虑到实际就是多了个空列,就不管了。实际的数据是一样的就行。
最后附上python代码
"""
这是一个读取xlsm然后写txt的文件,为了省去批量处理的时间。
以实例的表格上试过了,和手动上基本上是一致了,除了其中一张子表不知为何手动保存“制表符格式txt”会在行尾多一个制表符,逻辑没搞懂。但是不影响使用,因为无非是那个手动保存的行尾多了个空列
"""
import openpyxl
import os
输入目录 = '' # 根据自已的目录路径更改,要另存的数据目录
输出目录 = '' # 根据自己的目录路径更改,生成的txt文件会放在这个目录下
# 获取目下的所有xlsm文件的列表
xlsm列表 = [f for f in os.listdir(输入目录) if '.xlsm' in f]
print('目录下的xlsm文件列表:', xlsm列表)
for f in xlsm列表:
输入文件 = os.path.join(输入目录, f)
print(f'当前文件路径:{输入文件}')
工作簿 = openpyxl.load_workbook(输入文件, data_only=True) # data_only确保公式是要公式还是值
工作表之集 = 工作簿.sheetnames
for 工作表之名 in 工作表之集:
总文本 = ""
文本 = [] # 清空变量,之后读取数据,写入用
print(工作表之名)
工作表 = 工作簿[工作表之名]
# print(工作表)
表最大行数 = 工作表.max_row
for 行数 in range(1, 表最大行数 + 1):
行文本 = []
for 单元格 in 工作表[行数]:
# 单元格有值,处理值,无值留空
if 单元格.value or 单元格.value == 0 or 单元格.value == "":
# 仿WPS制表符txt逻辑
## 有些特殊字符要加双引号",而双引号内的双引号要用 "" 来转义
if isinstance(单元格.value, str) and (',' in 单元格.value or "\n" in 单元格.value ):
行文本.append('"' + str(单元格.value).replace('"', '""') + '"')
if 单元格.value == "\t":
print('1')
elif isinstance(单元格.value, float):
# print("f:",单元格.number_format)
# wps逻辑,默认保留2位小数,以及超过一定长度,显示科学计数
if len(str(单元格.value)) > 10:
行文本.append("%.5E" % 单元格.value) # 大于一定位数的,用科学计数法表示,保留5位精度
else:
行文本.append("%.2f" % 单元格.value) # wps默认保留2位小数
elif isinstance(单元格.value, int):
# print("d:",单元格.number_format)
if len(str(单元格.value)) > 10:
行文本.append("%.5E" % 单元格.value) # 大于一定位数的,用科学计数法表示,保留5位精度
elif 单元格.number_format == '0.00':
行文本.append("%.2f" % 单元格.value)
else:
行文本.append("%d" % 单元格.value)
else:
行文本.append(str(单元格.value))
else:
行文本.append("")
文本.append("\t".join(行文本))
总文本 += "\r\n".join(文本) + "\r\n" # windows式换行
输出文件名 = os.path.join(输出目录, 工作表之名)
with open(输出文件名, 'w') as 文本文件:
文本文件.write(总文本)