顯示具有 回憶 標籤的文章。 顯示所有文章
顯示具有 回憶 標籤的文章。 顯示所有文章

2010年7月12日 星期一

Perl學習之旅的回顧(之四)

從大學時代初次學習Pascal程式語言開始,以及後來陸續學習的Fortran、C、Basic、FORTH以及Perl都是屬於指令式程式設計 (Imperative programming),也就是一步一步告訴電腦如何執行我們所設計的程序。

到今天我還記得Pascal教科書上讓我印象深刻的那句話:「Algorithms + Data Structures = Programs」。非常古典的看法,它宣告著,有了演算法加上適當的資料結構,等於擁有了通往電腦魔法世界的鑰匙;在當時,這似乎是永恆的真理,畢竟,美國太空總署透過Fortran,神奇地把太空人送上了月球,不是嗎?

但一般程式語言所提供的資料結構是平凡、單調而且僵固的。Pascal的資料結構尤其讓我倒胃口,不但要事先宣告型態與大小,而且又有許多的語法限制,在產生神奇的魔法效果之前,得先經過編譯器(Compiler)黑森林的重重刁難之後,才能勉強執行,更困難的是,想要把現實世界的東西,塞進電腦世界的資料結構裡面,沒有添加一點想像力,耐心的迂迴前進是不容易辦到的。

Perl 的資料結構,基本上說來是蠻單純的,但神奇的是,透過Reference的使用,可以建構成相當複雜有用的資料結構,除了之前所提到的聖經內容,也可以是一個網頁內容的樹狀結構,或者,把一間公司所有網路設備的資料放入資料結構裡。使用過這樣強大又具彈性的資料處理能力,再參考以下範例,終於可以體會這句話的意思:Algorithms + Data Structures = Programs。
use strict;
use LWP::Simple;
use HTML::TreeBuilder;

my $html=get("http://www.apress.com");
my $tree=HTML::TreeBuilder->new;

$tree->parse($html);
$tree->eof;

my @pnodes=$tree->find_by_tag_name('meta');

foreach my $node (@pnodes) {
    print $node->as_HTML;
    print "\n";
}

$tree->delete;

變化是無止盡的,接下來「物件導向程式設計」概念,衝擊著習慣第三代程式語言的程式設計師們,然而Perl並沒有拋棄我們,程式設計的原理原則是不會變的,它只是不斷地融合再生,就像上面的範例,就是不折不扣的物件導向程式呢。

為什麼需要「物件導向程式設計」,我認為最重要的原因之一是,藉由抽象所帶來的單純化,讓程式碼容易撰寫(模組化)、容易維護及reuse。我們不需要知道,如何去剖析組成網頁的HTML內容,也不用知道剖析後的資料結構,只要知道如何透過物件的介面去使用就可以了。

Moose 是Perl的一個模組,它讓我們可以撰寫 Perl物件導向程式。我試著把之前所建立DBM::Deep裡的聖經資料,加上物件的介面,我們便可以提供一個間單的讀經介面。

# Bible.pm
package Bible;

use Moose;

use DBM::Deep;
use List::Util qw(max min);

# 透過變數$bible連結DBM::Deep檔
my $bible = DBM::Deep->new( "bible_ary.dmd" )->{bible};

#properties
has readbook   => (is => 'ro', isa => 'DBM::Deep', writer => 'set_readbook');
has opened     => (is => 'ro', isa => 'Str',       writer => 'set_opened');
has pointer    => (is => 'ro', isa => 'Int',       writer => 'set_pointer');

has nBooks     => (is => 'ro', isa => 'Int', default => $#{$bible});
has booklines  => (is => 'ro', isa => 'Int', default => 0, writer => 'set_booklines');

#methods
sub open {
    my $self = shift;
    my $book = shift || '創世紀';
 
    if ($self->findbook($book)) {
        print $self->opened, " opened\n";
    }
    else {
        print "$book not found!!\n";
    }
}

sub findbook {
# 由篇名尋找
    my $self   = shift;
    my $tofind = shift;

    for my $index ( 0 .. $self->nBooks )  {
        if (   $bible->[$index]{bookname}{chn} eq $tofind 
            or $bible->[$index]{bookname}{eng} eq $tofind ) {

            $self->set_readbook ( $bible->[$index]{words} );
            $self->set_opened   ( $tofind );
            $self->set_booklines( $#{$self->readbook} );
            $self->set_pointer  ( 0 );

            return 1;
        }
    }

    # mark no book opened 
    $self->set_booklines( 0 );
 
    return;
}

sub read {
    my $self  = shift;
    my $nline = shift || 10; # 一目十行 

    my $from;
    my $to;

    return unless $self->booklines;
 
    $nline = 10 if $nline < 0;
 
    for (0 .. $nline - 1) {
        $self->readline;
        $self->incre_pointer;
        last if $self->pointer == $self->booklines;
    }

}

sub incre_pointer {
    my $self = shift;
    $self->set_pointer( min( $self->pointer+1, $self->booklines ) );
}

sub readline {
# 顯示現在pointer所指向的那一行
    my $self = shift;
 
    printf "%-5s %s\n",
            $self->readbook->[$self->pointer]{index},
            $self->readbook->[$self->pointer]{word},;
}

sub lookup {
# 翻閱至特定章節。 例.chapter(3,2) 第三章第二節
    my ($self, $chap, $chap_sub) = @_;
 
    for my $line (0 .. $self->booklines) {
        my ($r_chap, $r_chap_sub) = split /:/, $self->readbook->[$line]{index};
        if ($r_chap >= $chap && $r_chap_sub >= $chap_sub) {
            $self->set_pointer($line);
            $self->readline;
            last;
        }
    }
    return;
}

1;


有了Bible這個物件之後,我們的程式就不需要知道DBM::Deep或者YAML裡聖經章節的資料結構,只要透過物件去使用就可以了(就算以後我把聖經放到雲端資料庫裡面也是一樣!)。

use Bible;

my $bible = new Bible;

$bible->open('馬太福音');
$bible->read();

$bible->lookup(2,5);
$bible->read();

物件導向不是萬靈丹,它是程序導向方式的演化,良好的抽象介面,讓內部的細節隱藏,以便因應日趨複雜的資訊系統。

"Easy things should be easy and hard things should be possible".

這幾年來,我從學習Perl中得到許多知識與樂趣,也由於資訊領域快速發展的特性,讓我可以經常的藉由Perl去探索新的事物。學習是無止盡的,如果學習過程能夠充滿了樂趣,我們會高興知道這個事實,並且樂在其中。

後記. 之所以會寫這幾篇Perl學習之旅的網誌,是因為前兩個星期,無意間知道這個模組Number::RecordLocator 所引起的。

2010年7月5日 星期一

Perl學習之旅的回顧(之三)

YAML檔透過縮排來表示資料間的相互結構關係,但每次要使用的時候,還是要透過LoadFile函式來剖析並載入記憶體才能夠使用。
所以會有使用前處理的overhead以及記憶體的限制,雖然對於幾萬筆(或10幾萬筆)的資料,這個問題還不算嚴重,但畢竟還是個限制。
另外還有一個問題,就是當我們要透過程式來更改YAML檔的內容時,就會有鎖定(Lock)的問題,因為實際上,這個YAML檔也可能被其他人(程式)所讀取。

以上所描述並不是YAML的問題,應該說是它的特性(與XML類似),所以YAML檔大部分用於設定參數檔(configuration file),由人去目視編輯內容(類似WIndows的INI設定檔,又比XML具可讀性),再由程式讀取使用。

但是有時候,我們就是需要處理幾十萬到幾百萬筆以上的資料,又要能讀能寫,記憶體又有限制的時候,到底該怎麼辦? 除了使用資料庫之外,Perl提供了一種方法:DBM::Deep

簡單的說,DBM::Deep是一個Perl位於CPAN上的模組,經由它所建立的純量變數,可以神奇將Perl的資料結構對應到磁碟上的一個檔案,可讀可寫,還有lock的功能,同時也提供Transaction的機制,最重要的是,不管資料量的大小,都不會有記憶體限制的問題(當然,我們不會用這個方法來處理幾GB以上的資料)。

舉個例來說,我們由YAML檔將整本聖經讀入之後,可以存成DBM::Deep的格式,之後,我們就可以將讀經的心得,寫入到DBM::Deep檔案內,讓心得跟聖經經文之間產生連結,如以下程式碼:

use strict;
use DBM::Deep;
use YAML qw /LoadFile DumpFile/;

my $db = DBM::Deep->new( "foo.db" );

# 將所有舊約內容讀入$bible純量變數內
my $bible = LoadFile('bible_old.yaml');

my $db = DBM::Deep->new( "bible.db" );
# 執行以下程式碼時, bible.db已存有所有舊約內容
$db->{bible_old} = $bible;

# 加入我對於箴言的心得, 就這樣!! 所有改變已經存於硬碟上了
$db->{bible_old}{'old-20'}{memo} = '我最喜歡的經文'; 

DBM::Deep的資料結構屬於 hierarchical階層式資料形式,透過節點(key)的方式往下尋找下一階層的節點,直到找到所需要的資料為止。






















但與一般階層式資料庫不同的是,DBM::Deep可以動態產生資料結構,而又能擁有資料的持續性(persistence),這種特性可以應用在不同程式之間的資料儲存,交換,這是一種簡易型,輕量級又極富彈性的資料庫。

Perl再一次拓展了我對於資料處理的知識與視野。

2010年6月30日 星期三

Perl學習之旅的回顧(之二)

要檢索文字,必須知道什麼是「常規表示式」(Regular Expression),這是我透過Perl認識的一樣奇特的知識。
也因為能夠在Perl程式中簡單隨意的使用常規表示式,所以很快的便摸熟了一些基本的用法,這種可以方便實驗(Edit & Run)的學習模式,提昇了吸收新東西的速度。

雖然之前已經能夠快速的讀入聖經文字檔,使用常規表示法來檢索聖經內容,但是我沒有辦法區分新約與舊約、列出特定連續章節、中英文對照等等,原因是,原始文字檔案只有文字本身而沒有結構!

YAML 」是另外一個奇特的東西。

簡單的說,YAML是human-readable的類XML,透過資料的縮排,來代表(imply,也符合人類視覺的直覺)資料間的從屬、順序、對應等關係。

我將原來的檔案整理成YAML檔結果就像下面這個樣子。
<<舊約>>












<<卷名>>














有了YAML文件後,如果要知道舊約有幾篇,新約又有幾篇,可以使用以下程式碼:
use strict;
use YAML qw /LoadFile DumpFile/;

# 將聖經目錄讀入$bindx純量變數內
my $bindx = LoadFile('bible_index.yaml');

my $nOld = grep { /old/ } keys %$bindx;
my $nNew = grep { /new/ } keys %$bindx;

printf "聖經裡面,舊約有%d篇,而新約有%d篇。\n", $nOld, $nNew; 
輸出結果:

聖經裡面,舊約有39篇,而新約有27篇。

如果要列出《箴言》內容,可以使用以下程式碼:
use strict;
use YAML qw /LoadFile DumpFile/;

# 將所有舊約內容讀入$bible純量變數內
my $bible = LoadFile('bible_old.yaml');
my $bindx = LoadFile('bible_index.yaml');

my $old_20 = $bible->{'old-20'};

printf "《%s》\n", 
$bindx->{'old-20'}{chn};

for my $index ( sort keys %{$old_20} ) {
    printf "%s %s\n", 
            $index, 
            $old_20->{$index}{word};
}
輸出結果:

《箴言》
001:001 以色列王大衛兒子所羅門的箴言.
001:002 要使人曉得智慧和訓誨.分辨通達的言語.
001:003 使人處事.領受智慧、仁義、公平、正直的訓誨.
001:004 使愚人靈明、使少年人有知識和謀略.
001:005 使智慧人聽見、增長學問、使聰明人得著智謀、
001:006 使人明白箴言和譬喻、懂得智慧人的言詞和謎語。
001:007 敬畏耶和華是知識的開端.愚妄人藐視智慧和訓誨。
......
......

透過YAML建立了Perl的內部資料結構之後,如果有需要轉成XML格式檔,也是相當直覺與容易的,如下。
use XML::Simple;
# 存成XML格式檔
open my $fh, '>', 'bible_old_20.xml' 
    or die "$!";
XMLout($old_20, OutputFile => $fh);

close $fh;
XML檔案內容:


<001:001 index="1:1" word="以色列王大衛兒子所羅門的箴言." />
<001:002 index="1:2" word="要使人曉得智慧和訓誨.分辨通達的言語." />
<001:003 index="1:3" word="使人處事.領受智慧、仁義、公平、正直的訓誨." />
<001:004 index="1:4" word="使愚人靈明、使少年人有知識和謀略." />
<001:005 index="1:5" word="使智慧人聽見、增長學問、使聰明人得著智謀、" />
<001:006 index="1:6" word="使人明白箴言和譬喻、懂得智慧人的言詞和謎語。" />
<001:007 index="1:7" word="敬畏耶和華是知識的開端.愚妄人藐視智慧和訓誨。" />
......
......

在學習Perl的過程中,我知道了YAML以及XML這兩種新的文字資料格式,雖然這兩種格式背後仍有許多細節、應用與注意事項,但經由這些小小的練習,讓我有了熟悉的感覺,建立起學習更多細節的信心,而不再是難以入門的鬱卒。(這是我曾經看了一本「XML入門」之後的感覺)

參考文章: XML Matters: YAML improves on XML

2010年6月28日 星期一

Perl學習之旅的回顧(之一)

自從2001年接觸Perl這個程式語言,許多方面的知識跟Perl產生了連結之後,好像會變得比較容易理解,對我而言,這是個感覺奇妙的學習之旅。

從一開始,Perl的資料結構:scalar純量、array陣列以及hash雜湊,簡化了程式的撰寫與資料處理的力量,經由這三類資料型態,可以處理大部分的問題。

Perl的處理速度以及記憶體管理也讓我對於資料處理有著深刻的印象。

舉個例子來說,我初學Perl的時候,由於已有其他程式語言的經驗,
所以看了一些語法之後,想要寫個程式來試試看,但又不想寫什麼迴圈九九乘法表之類的,
於是想到"聖經",聖經可以線上下載取得,中英文都有,內容文字量也夠多,
處理起來應該比較趨近於實務狀況。

實際下載後,文字檔大小約3.5MB(31,102行),摘錄部份內容如下:

Gen 1:1 起初 神創造天地。
Gen 1:2 地是空虛混沌.淵面黑暗. 神的靈運行在水面上。
Gen 1:3  神說、要有光、就有了光。
Gen 1:4  神看光是好的、就把光暗分開了。
Gen 1:5  神稱光為晝、稱暗為夜.有晚上、有早晨、這是頭一日。
Gen 1:6  神說、諸水之間要有空氣、將水分為上下。
Gen 1:7  神就造出空氣、將空氣以下的水、空氣以上的水分開了.事就這樣成了。
Gen 1:8  神稱空氣為天.有晚上、有早晨、是第二日。
Gen 1:9  神說、天下的水要聚在一處、使旱地露出來.事就這樣成了。
Gen 1:10  神稱旱地為地、稱水的聚處為海. 神看著是好的。

我就試著寫一個聖經全文檢索程式,而整個程式碼及執行結果讓我覺得很神奇,如此簡潔、如此快速,程式如下。
use strict;

open BB ,'<', 'hb5_utf8.txt'
    or die "$!";

# 將檔案內容全部置於陣列變數@bible)內
my @bible = ;
close BB;

while (1) {

    print "請輸入查詢文字(q=結束):";
    my $search = ;

    chomp $search;

    exit if $search =~ /q/i;

    for my $words (@bible) {
        print "$words" if $words =~ /$search/o;
    }

}


執行結果

perl bible_demo.pl

請輸入查詢文字(q=結束):憂傷

Gen 6:6 耶和華就後悔造人在地上、心中憂傷
1Sa 2:33 我必不從我壇前滅盡你家中的人.那未滅的必使你眼目乾癟、心中憂傷.你家中所生的人都必死在中年。
2Sa 12:18 到第七日、孩子死了。大衛的臣僕不敢告訴他孩子死了、因他們說、孩子還活著的時候、我們勸他、他尚且不肯聽我們的話、若告訴他孩子死了、豈不更加憂傷麼。
Psm 51:17  神所要的祭、就是憂傷的靈. 神阿、憂傷痛悔的心、你必不輕看。
Psm 69:29 但我是困苦憂傷的. 神阿、願你的救恩將我安置在高處。
Pro 17:22 喜樂的心、乃是良藥.憂傷的靈、使骨枯乾。
Pro 18:14 人有疾病、心能忍耐.心靈憂傷、誰能承當呢。
Ecc 1:18 因為多有智慧、就多有愁煩.加增知識的、就加增憂傷
Isa 16:7 因此、摩押人必為摩押哀號.人人都要哀號.你們摩押人要為吉珥哈列設的葡萄餅哀歎、極其憂傷
Isa 54:6 耶和華召你、如召被離棄心中憂傷的妻、就是幼年所娶被棄的妻.這是你 神所說的。

請輸入查詢文字(q=結束):

有了這麼一點小成果之後,我對於Unix世界充滿了信心,
自以為有了Perl的協助,自己將無所不能,
直到我發現自己苦心撰寫的程式,
其實在Shell底下,只要一行指令就可以做到一樣的結果時,
我有點傻了。

    grep 憂傷 hb5_utf8.txt

那時突然覺得資訊的世界不僅僅是DOS/Windows的世界,
這世界的範圍、力量,遠比我當時可以想像的大多了。

2010年5月11日 星期二

最珍貴的禮物

前幾天買了台華碩的桌上型個人電腦 (AMD雙核心/2G+2G /500G)以及華碩22"螢幕,總價不到二萬。隨後想起20幾年前剛退伍沒多久時,曾向媽媽拿了約七萬元買了一台PC-AT/386。

現在想起來,有點詫異,為什麼那時會買得下今日仍然覺得很貴的電腦?(其實拿來打電玩居多)

母親節前夕,媽媽仍然一如以往的婉拒了不必要的禮物,只盼望我們一家人能經常保持快樂的心情,健康平安的生活,保持信仰,接近神。

想起曾看過一句話:「無條件的愛是我們所能給予的最珍貴的禮物」。
"無條件"是個奇妙的詞,它能讓人心溫暖,感受關懷,帶來希望。

而這份最珍貴的禮物,其實是我們每個人都有能力給予的,衷心期盼對於自己的家人、朋友,我能夠經常地送出這份禮物。

2010年4月28日 星期三

我所感覺美好的一切

我覺得人生是美好而又充滿快樂回憶的。

最近的一次這樣的感覺,
應當是去年聖誕夜那天在聯合報上所看到的這篇文章《聽巴哈》


文章一開始便這麼寫著:「所有精美的東西都帶有一點脆弱的特性,而巴哈的音樂一點也不脆弱,經聽耐聽,久聽也不覺得膩……


當下感覺,寫得真好!
是真的嗎? 有人跟我一樣,是這樣恣意的享受著"經聽耐聽"的巴哈的音樂嗎?

然而,談到巴哈,也許該將記憶拉回到大學時期,室友王益文帶來的那卷《大提琴無伴奏組曲》,或者更早,高一時,無意間在開唱片行同學的家中所聽到的《賦格的藝術》以及同學大姐不可置信的望著我說的一句話:「你喜歡聽這種音樂喔!?」

好久以前的事了,但記憶卻又是如此的鮮明與深刻,或許,我是某種類型的怪胎,但,幸運的是,我很早自己就發現了,而且持續享受著這專屬的滿足。

由於好奇使然,一方面也得力於網路的豐沛資訊,我查到這篇投稿文章的作者「周志文」曾出版了幾本書,而且也還買得到!

從博客來訂購了「同學少年」閱讀之後便喜歡周教授的文筆與思維,那種幽默、悠淡、靜雅的文筆風格深深的吸引了我,便陸續訂購了幾本如「時光倒影」、「冷熱」、「記憶之塔」、「布拉格黃金」等書,快樂而又期待的追逐著。文章內充滿著智慧的觀察、內斂的省思、豁達的見解,就像我的良師益友一樣,讓我近幾個月來的生活裡充滿了樂趣與收穫。

由「同學少年」的推薦序,知道了與我同年的「張瑞芬」教授,也好奇的買了她的一本書「鳶尾盛開」,這本書不但評論的非常好,也介紹了許多我之前不熟悉的作家與好書,所以接著我又買了一本詹宏志的「綠光往事」、曾郁雯的「京都之心」等。

由一篇副刊文章,接二連三引發的閱讀歷程,
閱讀後與作者間的心意相通,讓我心滿意足,
覺得人生如此美好與富含意義,
每一件事都與之前的事物相關連,
雖然我們都是孤獨而獨立的生活著,生命得用自己獨特的方式與速度熟成,
但是人與人之間卻又一直是相依而又相互影響著。

我覺得每個人的人生都是美好而又充滿快樂回憶的,
但這美好的過程,
需要我們自己來追尋探索
並留住每一個美好的片刻。

2010年3月13日 星期六

Jeremy




關於這部電影
其實我已經完全沒有印象了
充其量
還只記得男主角的近視眼鏡有夠"土"的
像我小學時的一位博學同學

但這首曲子則是印象鮮明
特別是旋律一直深印腦裡
偶爾也會出現重複播放
可能是歌詞也算簡易
竟然也能夠回憶大半

Youtube實在也有夠厲害的
什麼都找得到
cool~

2010年1月23日 星期六

Famous Blue Raincoat - Leonard Cohen



十幾年前,偶然的機會裡面,買到Leonard Cohen的一片CD,
這首曲子也就這樣聽了十幾年,
心情好的時候聽
心情壞的時候也聽
工作的時候聽
休息的時候也聽
算是種奇妙的喜愛與緣分吧

歌詞沒研究
只聽到滿滿滄桑的情緒
物我兩忘
木已成舟
萬事不能強求
刻畫的傷痕已然存在......

2009年11月11日 星期三

紳士幻想曲



記得第一次聽到這首曲子是我高中的時候
神奇的是    每次聽的感覺幾乎都是一樣的
充滿著高貴自在的情緒
勇敢無懼又柔情的調性

音樂跟文字都是很奇妙的
能觸動你的心弦
能讓你進入時光的隧道
回憶起年少時期的種種

記得大學時喜歡讀楊牧的散文
也記得他曾寫過的一段話:

    幸福
    並非不可能
    你要它
    它就來了


隨著年歲漸長
就越能體會
這段話的含意

幸福就是勻稱的心境起伏

就在你自己家裡面啊