以Ruby為代表的腳本語言常被用來進行文本處理。為了能對她有個感性認識,我們先給出第一道例題教您使用“grep”命令,其功能就是從文本中找出符合正則表達式的行。
grep命令用法如下。
grep pattern file...省略文件名時則從標準輸入搜索合適的行。
若用Ruby(簡單地)改寫的話,就像下面這樣。
$pat = ARGV.shift while gets print if /#{$pat}/ end雖然只有4行,但卻是很不錯的程序。Ruby是解釋型語言,所以不需要編譯馬上就能執行您寫的程序。Ruby從一開始就添加了各種各樣的便利的功能,如讀取參數指定的文件以及使用正則表達式進行檢索等,使編程變得“簡便快捷”。
假如用C語言重寫這段程序的話,即使去掉正則表達式部分也會相當長。若非編程高手則將花費不少的時間。這種“簡易性”正是Ruby的長處之一。
下面就來運行一下吧。
ruby grep0.rb ruby /usr/dict/words ruby效果不錯(太好了,太好了)。
為了對Ruby有所了解,我們仔細看看這段程序。
像grep那樣讀取文件并逐行處理然后輸出結果的程序基本上由下列部分構成。
while 讀入一行 處理讀入的行 輸入處理結果(若有的話) endRuby從一開始就包含這些功能。例如,“讀入一行”可以使用gets函數,輸出結果可以使用print函數。
前面的程序也遵循這種形式,讓我們仔細研究一下。
1 $pat = ARGV.shift 2 while gets 3 print if /#{$pat}/ 4 end第1行從命令行參數中取出比較模型(pattern),然后賦值給變量$pat。Ruby的命令行參數都保存在數組ARGV中,所以取出數組的第一個元素。ARGV.shift表示去掉數組第一個要素。
第2行的”while gets”幾乎是一種固定用法,表示一行一行地讀取數組ARGV中命令行參數指定的文件。若ARGV中包含不止一個文件名時,則從最初的文件開始依次讀取每一個文件。
第3行表示,若出現符合pattern的行就print。/#{$pat}/表示將讀入的行與$pat所代表的正則表達式進行比較。
‘#{$pat}’表示把’ #{’到’}’之間的表達式置入正則表達式(/.../)中。這種置入表達式的方法在字符串或正則表達式中都有效。
第4行的“end”與第2行的“while”呼應,表示由while開始的循環到此為止。
您是不是明白了呢?程序雖短,卻有些難懂吧。實際上,Ruby允許您使用各種簡寫形式以確保程序更容易書寫。因此,程序雖然變短了卻也變得更佳難懂了,不過這也是沒有辦法的事。下面,我們就把省略的部分補上,再把程序重寫一遍。
1 $pat = ARGV.shift 2 while $_ = gets() 3 if $_ =~ /#{$pat}/ then print $_ end 4 end好像并沒有好懂多少嘛。但是剛才被省略掉的變量“$_”浮出水面后,程序的運行原理好像變得容易理解了。
那么,我們再次詳細地說明一下。
第1行還是一樣。
第2行的gets很明顯是函數。gets讀取一行后賦值給變量$_。若到達文件尾部時返回false,則while循環結束。
第3行變化較大。首先,if的形式變了。Ruby中的if有兩種表達形式(意義相同)。第一種是后置形式,前面的程序即是如此。第二種就是該程序中出現的前置形式,以end結束。另外,前置形式中還有else部分,可以指定當條件不成立時程序應該執行的代碼部分。后置形式中沒有else部分。
其次,if的條件部分(if和then之間的部分)也變了。條件部分中出現的正則表達式可看成是和變量$_進行比較的簡略寫法。這次的程序沒有對此進行省略。=~是比較字符串和正則表達式時使用的操作符。
最后一個不同是這次指定了print的參數。當print的參數被省略時,將輸出變量$_的值。
第4行也沒有變化。
現在看一下這個程序的運行速度。
% time ruby /tmp/grep0.rb ruby /usr/dict/words ruby 5.89user 0.25system 0:06.17elapsed這種程序在i486DX4 75MHz的環境下竟然用了6秒多,真的有點慢呀。下面再和普通的grep比較一下。
% time grep ruby /usr/dict/words 0.03user 0.06system 0:00.13elapsed嗯,還是慢呀。要說Ruby慢也情有可原。畢竟Ruby是解釋型語言,和經過編譯的專用程序grep比起來還是慢一些。話雖如此還是覺得太慢,下面就把程序提速一下。
這就是提速后的程序grep1.rb。
1 $pat = /#{ARGV.shift}/ 2 while gets 3 print if $_ =~ $pat 4 end第1行和第3行變了。不再每次都重新生成正則表達式(默認情況下,//每次都重新生成正則表達式對象),而是將正則表達式賦值給變量后反復利用,因此程序速度得到提升。
若if的條件表達式不是正則表達式的話,就不會自動和變量$_進行比較,所以必須使用’=~’進行比較。
% time ruby /tmp/grep1.rb ruby /usr/dict/words ruby 2.26user 0.12system 0:02.39elapsed運行時間大約縮短了一半,即使如此,比起grep來還是太慢了。
那么,這個“磨磨蹭蹭”的grep程序還有什么意義呢?編程雖然簡單,但是比普通的grep慢那么多,好像沒什么用處呀。
這個程序的存在意義就在于它是由這四行代碼構成。也就是說,您可以簡單地擴展其功能。而用C語言編寫的專用程序grep就不行,充其量也只能靠選項來調整部分功能罷了。
例如,我們可以再寫一個反顯符合條件部分的程序。
1 st = "\033[7m" # 反顯開始轉義序列 2 en = "\033[m" # 反顯結束轉義序列 3 4 $pat = /#{ARGV.shift}/ 5 while gets 6 if $_ =~ $pat 7 # 在符合條件部分的前后置入轉義序列 8 gsub! $pat, "#{st}\\&#{en}" 9 print 10 end 11 end程序變得有些復雜了,但這樣就能把符合條件的部分反顯出來。Ruby就是那種可以輕松地實現您所追求的功能的理想工具。
雖然她的運行速度稍慢,但您可以迅速快捷的編程運行并得到結果。從整體上來看,這往往可以助您提早達到目標。這正是以Ruby為代表的腳本語言的強項。若您的開發項目對于運行速度要求很高的話,您可以多花些時間再提高程序的運行速度。
下面,我們來總結一下剛才所學的東西。
Ruby語言是解釋型語言。 使用Ruby可以輕松地編寫出功能復雜的程序。 Ruby的開發速度快過C等語言,但運行速度慢。原文轉自:http://www.anti-gravitydesign.com