想說一下我自己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文件。
幾點說明:
1,這個函數跟腳本就不一樣了,你只需要給別人這個接口,以及函數文件別人就可以直接調用你的文件而不必關心你寫了什麼。更不需要關心你們兩個的腳本之間是否有重複的變量名。
2,第二行開始的注釋最好是寫成有關本函數設計的介紹或者函數接口調用方式,這樣別人使用這個函數文件時候只要是原始碼就能夠直接使用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.
自己的版本信息等內容可以空一行,以注釋的形式寫在下面。
3, 再次說明,這只是一個簡單的演示,距離實用還是有很大的改進空間(比如圖片,比如格式,比如排版等處理)。
4, MATLAB在識別函數的時候其實首先識別的是文件名,所以,函數名跟文件名得寫成一致。
5, 這不是腳本,確實是不能直接運行,在調用的時候會實現相應的功能。
6,代碼中沒有任何clear以及clc的命令,但是你會發現數據空間中沒有變量運行的痕跡留下。這就是函數化的一大好處的體驗,彼此的運行空間似乎是獨立的,腳本中的信息也不會受此影響。
7,如果考慮到設計較為完美的程序,這裡面還需要加入各種異常的處理。這是我學習Python的時候學到的一種編程哲學,我覺得確實是很有必要。我們考慮的設計,不應該局限於當前,確實是應該擴展眼界看到很久以後。
資訊 · 共享 · 互助
模擬仿真的服務型媒體
微信號:sim_ol