唠唠python(8) -- 使用脚本代替手工数据操作

这个问题已经过了很多天了,都记不太清细节了。

先捋一捋我们的需求。

需求

待处理表格

这个表格有点熟悉,好像在之前的文章里看到过。我们还是以它为例子。

我们有一张如上的物料订单表格。每两行对应一种物料,即需要的料数和订购的料数。不同的列对应不同时期需要的物料数量。

因为供应商提供给我们的物料都是以10000为单位的,所以就算我们只需要9颗料,也要订购10000颗料。也就是以10000为单位,对料数上取整。

我们看到其中有一些表格的数量是红颜色,它表示这些数据已经被手工填写了。每个单元格的料数以10000为单位上取整后,被填入它下面的一个单元格。

计算公式

我们在之前的文章里已经给出了订单数量的计算公式:(n+10000-1) / 10000 * 10000,其中n为需要的实际数量。

功能清单

我们列一下需要的功能清单:

  1. 打开或保存excel文件
  2. 读取或写入单元格

再不需要其它的功能了。

上一篇讲到的openpyxl很好地实现了我们需要的这些功能。

打开excel使用workbook = openpyxl.load_workbook("excel文件位置"),保存使用workbook.save("保存到的路径")

读取某个单元格使用print sheet["B5"].value,写入某个单元格使用sheet["B5"] = 30000。其中sheet是我们使用workbook.active获取的工作簿里的第一张表格。

几点逻辑

我们需要对上面的表格中,I3到S28的奇数行数据查看一遍,还需要根据单元格的内容和它下面一个单元格的内容来判断是否需要处理单元格数据。

挨个查看一遍我们会用到一个这样的语句:

1
2
for row in range(3, 30, 2):
处理row行数据

这条语句的意思是,row分别等于3到28(不包含28)的奇数,然后依次执行下面的语句。后面的2是说,从3开始,取相隔为2的数。

这里有一点需要注意,我们的行号是数字表示的,但是列号是字母,我们需要先把字母转换成数字,在处理每一列时,再把数字转换成字母。庆幸的是,python已为我们准备好这些了。

1
2
3
4
for row in range(3, 30, 2):
for col in range(ord("I"), ord("U")+1, 1):
col_char = chr(col)
处理(row, col_char)单元格数据

ord()是将一个字母转化为数字,chr()是将数字转化回字母。注意我们给ord(“U”)加了一个1,因为ord(“U”)是不包含U的。我们再一次与python的作者来了一场完美的合作。

判断是否需要处理单元格,我们可以使用下面这条语句:

1
2
if sheet["I3"].value is not None and sheet["I4"].value is None:
处理I3单元格

意思也很好懂,翻译过来就是,如果I3单元格不是空的,并且它下面的I4单元格是空的,我们就处理I3单元格,并将处理结果填充到I4单元格。

实现脚本

说了这么多,其实脚本已经差不多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import openpyxl


workbook = openpyxl.load_workbook("a.xlsx")
sheet = workbook.active

def count_bill(n):
return (n+10000-1) / 10000 * 10000

for row in range(3, 30, 2):
for col in range(ord("I"), ord("U")+1, 1):
col_char = chr(col)

cell_src_idx = col_char + str(row)
cell_dst_idx = col_char + str(row + 1)

if (sheet[cell_src_idx].value is not None and
sheet[cell_dst_idx].value is None):
n = int(sheet[cell_src_idx].value)
sheet[cell_dst_idx] = count_bill(n)

sheet.save("b.xlsx")

14行代码,就实现了我们的需求。它读取当前目录下的a.xlsx文件,并根据我们之前所说的规则,处理指定范围内的表格数据,并将处理后的结果保存到一个新文件b.xlsx。

它真正将我们从枯燥无味的繁重工作中解放了出来,终于可以安心地睡个好觉了。

更好的脚本

当然,它还不够好,我们在这篇文章里不打算再把它变得更好,因为这个过程是很漫长的。但是它现在已经能帮我们节省比付出多几十倍甚至几百倍的时间。

它不够好,还能做怎么样的改进呢?

第一,里面全是代码,代码相对于人类自己的语言来说总没那么直观,毕竟我们是在迁就计算机嘛。

第二,每次执行时都要修改代码(输入输出文件名和单元格范围),十分之不友好。我们希望它可以让我们通过文件选择框选择某个文件,然后用鼠标拖选出我们要处理的范围,并询问我们要保存到哪个文件。

以上两点是显而易见的,特别是第二点。

不过最紧急的事情完成了,这个脚本已经可以帮我们节省下大量时间,以实现我们上面所说的改进了。

总结

终于把处理表格的傻逼工作交接给了计算机,可以舒一口气了。

为了不加重我们的心理负担,文章里有很多地方只是一带而过。至少对现在这个阶段来说,不需要知道的东西都是不重要的。如果哪里感到困惑,恭喜,这说明我们并不满足现状,想要一个更清晰的结果。

下一篇,我们先不急着改进上面说的两点不足,它们已经不那么紧急了,我们先来回顾一下之前提到的内容,并重新整理一下知识结构,让他们形成一个清晰的脉络,以便为以后装逼打下坚实的基础。

叶脉

碎碎念

零零散散地终于把这个脚本完成了,是时候回过头来梳理一下了。

小金约定,两天或两天以上的假期,每天一篇文章,失约100红包。本是想逼迫自己,竟然有时候写的不易乐乎,到了凌晨2、3点钟还在想读者会不会读懂这句话在说什么。

作者从读者的角度思考,读者又反过来从作者的角度思考,想想真的是一件很有趣的事情。

不得不说,写作的过程很快乐,虽然可能没有什么人看,但它至少已经帮助到了我。希望可以尽自己的一点微薄之力,让碰巧看到的人能生活得更轻松。