1689_MATLAB处理Excel文件提升篇
全部学习汇总: GreyZhang/g_matlab: MATLAB once used to be my daily tool. After many years when I go back and read my old learning notes I felt maybe I still need it in the future. So, start this repo to keep some of my old learning notes servral years ago. (github.com)
说明:下面所写不代表技术深度,只是个人经验之谈。如有问题,希望路过本文的人能够给我留言或者发邮件跟我交流。如果发现错误也请及时指正,我将十分感激!
Email:greyzhang@126.com Grey
想说一下我自己MATLAB M语言使用的进展阶段。最初使用的时候只是当做一个超级计算器使用,那是在大学的时候。后来工作中用到文件处理,慢慢就开始变成了脚本。而我理解的脚本含义就是毫无拘束,随便堆砌的一堆命令或者语句组合成的文件。如此一描述就知道它的特点了:写起来简单,因为在语法规则之外几乎是没有限制的;再就是确实是说不上什么结构,更不用谈什么架构。
虽然这个写起来的确是简单,不需要多么强的算法设计功底也不需要多么宽广的知识面,但是说到这种文件的维护那的确是一个噩梦。如果你一直在自己的圈子里那还是很好的,毕竟自己对自己写了一些什么还是很有了解的。但是倘若到了维护别人的脚本的时刻,有时候看了一半自己的决定通常是重写。重写也比修改要来得干脆,来得简单。
然而,说起来这倒不是M语言的缺陷。而是M语言本身优秀的同时又赋予了我们一定的自由度。不幸的是我们很多人让自由泛滥,最终的局面确实是变得有点不可控。我思考过为什么过去我自己工作那么忙,其实很多程度上就是这种方案或者思考的方式采用了拿来主义。不巧的是我的拿来主义所取的对象并不是一个很完美的对象,倘若我取的是某个软件大师的方式,或许现在的我不该是这个样子。而我自己在过去几个月总结出来的晋级方式应该是这样子的:命令à脚本à函数à面向对象。函数能够构建我们思考问题的方式,模块化我们的处理过程。而面向对象确实是能够让我们的东西在很大程度上得到了重用,而这一方面我做的明显不够好。
说的有些远了,谈一下这次晋级的主题——函数化
函数化也能够在一定程度上让我们的代码得到重用,至少是要比脚本好很多。而这种街口化的方式也适合模块化的作战,也能满足多人的协同。在MATLAB中有一点尤其让我觉得函数化很有必要——函数化过程中的变量全都可以理解为局部量或者静态量,也就是说它们不会被引入到数据空间。这样前面的处理过程跟后面的处理过程除了接口之外其他部分互不影响,能够简化调试复杂度,也能够让功能更加稳健。而做到这一切,唯一需要花一点点精力的就是函数的写法。其实,我觉得这比C或者Java简单的多。
函数的定义方式如下:
function [out1, out2, ...] = myfun(in1, in2, ...),其中参数都是可选的。
我觉得有一些通用的函数我们可以只写一次,做成函数以后只是调用就可以了。倘若是写成脚本,这些东西做起来基本上就只能够靠复制粘贴了。下面举个简单的例子,在处理Excel中一般如何使用函数。
下面来完成一个简单的Excel文件格式转换功能,目的是把07版以后的Excel文件转换成03版以及之前的兼容格式。也就是说xlsx扩展名转换成xls扩展名。这当然不是简单改个扩展名就能够实现的,这涉及到文件中的数据格式。我经常使用这个功能,我也用其他的方式实现了这个功能(不用盗版因此工作之余没有这么多的软件可以用,只能是用Perl或者Python等)。不过,MATLAB下实现的确是简单很多,因为写入数据的时候所有的数据转换都是由Excel完成的,而这也是做这个数据转换最稳妥的一个方式。转换成03版之前的版本有个好处,那意味着你将可以使用其他免费软件中的扩展库来处理Excel,那个也会有意思的多。
功能设计将会很简单,把Excel的内容读出来让后再重命名写回到新的文件。一切结束之后,把原来的文件删除。
>> ls
. Copy_of_data.xlsx xlsx2xls.m
.. data.xlsx
通过ls命令列出当前目录下的所有文件,其中data.xlsx是将要处理的文件,Copy_of_data.xlsx是备份的文件,xlsx2xls.m是这次写的程序。
程序代码如下:
function xlsx2xls(excel_file)
% This function can be used to convert a 2007+ version format excel file
% to a 97-03 version file. You can use this function by passing a excel
% file name with a string format to it.
% 2015.11.22 First written by Grey.
new_excel_file = strrep(excel_file,'.xlsx','.xls');
[~,sheet_names] = xlsfinfo(excel_file);
sheet_number = length(sheet_names);
for i = 1:sheet_number
sheet_name = char(sheet_names(1,i));
[~,~,raw_data] = xlsread(excel_file,sheet_name);
xlswrite(new_excel_file,raw_data,sheet_name);
end
delete(excel_file);
其中,第一行是函数的原型:此函数有一个传入参数,没有输出参数(正常设计的程序的时候我一般会加入参数,最起码会有处理异常时候的部分“诊断”信息返回)。
程序的第一行是把文件名处理了一下,把xlsx替换成xls获得了一个xls扩展名的文件名。这部分设计实际上有缺陷,因为文件名中本身也可能含有xlsx的字符串。比较好的方式是使用正则表达式,这里仅作演示不做那种复杂化处理。
接下来,先是读取了所有的Sheet页的名字,然后以页的方式向新的文件中写入按页读取的原始数据。
最后一行是对文件源文件的删除,最后只剩下“转换”后的文件。
在命令窗口输入xlsx2xls('data.xlsx');命令,很快处理结束。获得了一个97-03格式的Excel文件。
几点说明:
- 这个函数跟脚本就不一样了,你只需要给别人这个接口,以及函数文件别人就可以直接调用你的文件而不必关心你写了什么。更不需要关心你们两个的脚本之间是否有重复的变量名。
- 第二行开始的注释最好是写成有关本函数设计的介绍或者函数接口调用方式,这样别人使用这个函数文件时候只要是源代码就能够直接使用help命令查看你的功能介绍。比如,在命令窗口输入help xlsx3xls显示如下结果:
>> help xlsx2xls
This function can be used to convert a 2007+ version format excel file
to a 97-03 version file. You can use this function by passing a excel
file name with a string format to it.
自己的版本信息等内容可以空一行,以注释的形式写在下面。
- 再次说明,这只是一个简单的演示,距离实用还是有很大的改进空间(比如图片,比如格式,比如排版等处理)。
- MATLAB在识别函数的时候其实首先识别的是文件名,所以,函数名跟文件名得写成一致。
- 这不是脚本,确实是不能直接运行,在调用的时候会实现相应的功能。
- 代码中没有任何clear以及clc的命令,但是你会发现数据空间中没有变量运行的痕迹留下。这就是函数化的一大好处的体验,彼此的运行空间似乎是独立的,脚本中的信息也不会受此影响。
- 如果考虑到设计较为完美的程序,这里面还需要加入各种异常的处理。这是我学习Python的时候学到的一种编程哲学,我觉得确实是很有必要。我们考虑的设计,不应该局限于当前,确实是应该扩展眼界看到很久以后。