Vi/Ex編輯器教程[2]

helloxchen發表於2010-10-22

Vi/Ex編輯器教程

作者:Walter Alan Zintz
譯者:hq00e (at) 126.com
原文:

目錄

第二章:行模式地址

無論何時當你使用編輯器命令對當前文字的文字進行操作如刪除一些文字;將小寫字母改為大寫字母;寫入檔案(部分儲存)等等,的時候你得讓編輯器知道你要對哪一部份文字進行操作。少數的命令有內建的地址,大多數的行模式命令在使用者未指定地址時會使用預設的地址。但仍有許多情形下你必須知道如何給編輯器地址和給它什麼樣的地址。

許多行模式命令與可視模式下的相應命令是一樣的,它們是完成同樣工作的不同方式。重複的命令集的好處源於行模式與可視模式所提供的兩種截然不同的定址風格。截然不同的兩種定址方式意味著對於一種方式難於完成的編輯任務對於另一種方式可能只是小菜一碟。

我這樣一直提“行模式”,你可能會好奇是否真有一種單獨用於行編輯的模式。答案是:當然有。這種模式下你的螢幕不會為當前編輯檔案的文字所佔據,這個模式給你一個行模式的命令提示符――半形冒號(:),並只在螢幕上顯示檔案中的一特定行。這種模式給人的感覺就像是在shell提示符下使用UNIX命令一樣。現在已經很少人在行模式下編輯了,主要是因為在可視模式下你還能呼叫大多數的行模式命令,但在行模式下卻沒法使用可視模式命令。也可能因為可以在螢幕上看到檔案內容,並能即時檢視修改的文字的這種WYSIWYG(所見即所得)的感覺,更易於為大眾所接受。

但在有些情況下你仍需要暫時地使用行模式。要以行模式執行這個編輯器時可在Shell下輸入“ex”而不是“vi”來啟動這個編輯器。如果你已經在這個編輯器的可視模式中時可輸入“Q”來進入行模式。要回到可視模式,輸入“vi”然後按回車。

“vi”顯然是個行模式命令那你知道為什麼在輸入“vi”回到可視模式時我沒有在前面加上半形冒號嗎?原因是在行模式下輸入命令時並不需要那個冒號。輸入冒號甚至有害無益,行模式下如果在命令前輸入冒號,那麼在冒號和命令(不管是使用完整的命令或使用縮寫的命令)之間不能有地址也不能有空格――什麼也不能有。

基於以上的原因,在下面的行模式命令中將不帶冒號,你知道的――只有在可視模式下使用行模式命令才需要在命令前加上半形冒號。同時每個命令後我不再用“(ret)”來提醒你該命令要以Enter鍵來結束,因為你應該已經注意到了――不管是行模式還是可視模式下使用行模式命令都要以Enter鍵來結束。

有些人可能會問為什麼我要使用完整的命令形式,並使用了許多空格來分隔命令;為什麼不使用簡略的縮寫命令的形式。看看下面的例子,有兩行命令:

     global /^/ move 0
     g/^/m0

有一樣的作用,但第二個輸入起來肯定要快些,那為什麼在本教程中使用第一種形式呢?因為更長的版本更容易理解特別是當我在演示一些新概念時,並且這裡面的內容至少對某些人來講是新的。你很快會開始學寫編輯器指令碼,如果以簡潔的風格寫就指令碼的話,對未來維護指令碼的程式設計師而言這些指令碼會跟APL語言一樣難懂。所以你最好能瞭解一下這些命令的完整形式。在我介紹這些個行模式命令時我會告訴你該命令的完整名稱和一至二個的縮寫名稱。




行模式定址

單個地址。通常一個行模式命令只需要一個地址。一個地址就是指某一特定行,用以指示某些命令如刪除命令(delete)或替換命令(substitute)只對指定行進行操作。對於像插入命令(insert)或讀入命令(read)這種在當前行前或行後置入文字的命令而言使用多個地址則沒什麼意義。

搜尋式樣都是合法的行模式地址(在第一章中我們已經討論過搜尋式樣)。地址要放在命令的開頭,要置於命令名之前(如果在可視模式下使用行模式命令時地址則要放在開頭的半形冒號之後),所以:

     ?the [cC]at? delete

會將上一個包含字串“the cat”或“the Cat”的行刪除,而:

     /^GLOSSARY$/ read gloss.book

在當前編輯的檔案中從當前行開始往下找一行只包括一個單詞“GLOSSARY”的行,並將“gloss.book”檔案的內容置該行之後。

要重用與上次同樣的搜尋式樣作為地址有兩種簡寫形式。輸入“??”或“//”告訴編輯器使用上一次使用過的搜尋式樣,而“??”與“//”分別表示不同的搜尋方向用以代替上次使用的搜尋方向。也即,如果你輸入了:

     ?the cat? yank
     // delete
     ?? print

第二條命令會向下搜尋包含“the cat”的行並刪除,即使你最早使用搜尋式樣時的搜尋方向是向上。第三條命令會向上(往回)搜尋找到包含“the cat”的行並列印,這(湊巧)與最初搜尋的方向相同。

但這個透過簡寫形式(??或//)重用的搜尋式樣也許不是你用過的用來搜尋和定位行的式樣。如果你在某個式樣搜尋結束後執行一個替換(substitute)命令,那麼此時重用式樣使用的是替換命令用來指代替換文字的式樣而不是上一個用來定位行的搜尋式樣。如果你的替換命令用一個搜尋式樣開始作為進行替換操作的地址,然後在命令中指定要進行替換的式樣結果也是一樣的重用搜尋式樣時用的還是後一個式樣。因此如果你輸入了:

     /the cat/ substitute /in the hat/on the mat
     ?? delete

這時第二個命令會刪除上一個包含“in the hat”的行。要確保重用的式樣是上一個用來定位行的式樣(而不是上一個用來替換的式樣)可以使用“?”和“/”這兩種簡寫形式來向上和向下搜尋。在其它的情況下這個兩種簡寫形式與輸入“??”“//”的用處是一樣的。

行號也是有效的行模式地址。編輯器會自動地為檔案中的每一行進行連續地編號,這種編號是動態進行的,也就是當你增加或刪除行時編輯器會對插入和刪除點後的所有行重新編號。所以如果你對第46行的一些文字進行了修改並刪除了第11和12行時,你所修改的那一行現在變成了第44行。如果你又在第17行後增加了10行新行後,你修改過文字的那一行現在又自動變成了第54行。

所有的行號都是連續的不會有漏掉的或重複的行號,因此檔案中第n行的行號總是“n”,就是第七行的行號總是7,依此類推。(有許多方式可以用來顯示行號,這些內容我會在後面的教程中詳細的說明。)輸入以下命令就能刪除檔案中的第153行了:

     153 delete

在行號的周圍不需要使用任何的分隔符,除了搜尋式樣外在任何的地址周圍都不用使用分隔符。

還有兩個用符號表示的行號和一個虛構的行號也可用於行模式中的定址。只要在“緩衝”(譯者:可簡單理解為當前編輯檔案)中有任何一行文字(也就是你沒有編輯一個尚未存在且未輸入任何文字的檔案時),編輯器就假設你就在這兩個符號所表示其中一個地址中,通常最後一行會受最近一個命令所影響。一個半形句號或說是一點(.)是代表當前行的地址符號。而檔案中最後一行的地址符號是美元符號($)。因此如果你輸入了:

     . write >> goodlines
     $ delete

第一個命令會將當前行匯出並新增到名為“goodlines”的檔案末尾,而第二個命令會將編輯中檔案的最後一行刪除。

有幾個命令會在你給的行地址後置入文字:append (附加命令)命令就是其一。為了將文字置於檔案的開頭(如果你想把文字置於檔案的開頭的話),這幾個命令還能接受一個虛構的行號零(0)作為它們的地址。如果你想在檔案中所有文字之前輸入一些文字的話,以下的任一命令都可以做到:

     1 insert
     0 append

(注意:insert和append命令是不能在可視模式下透過前置一個冒號執行的少數行模式命令之一,因為加上要插入或附加的文字這兩個命令要佔用不止一行的空間。)

自己設定的行址。你可以為行分配小寫字母來作為行址,並且可以隨時改變這種分配。你甚至可以透過一個特殊的地址來返回上一次跳轉的行――這個地址是自動分配的。

用小寫字母標識特定行有許多方法,這些方法依行模式和可視模式的不同而有所區別。在後面的教程中我會逐一說明這些方法。一行一旦被做了標識則指代該行的行模式地址為半形單引號緊跟著用於標識行的小寫字母。輸入:

     'b print

會在螢幕上顯示你先前用字母“b”標識的行,不管該行與當前行的相對位置為何都能顯示該行。一個字母只能用來標識一行,所以不用告訴編輯器向上或向下搜尋編輯器總能找到那行。

編輯器自己也會做一些行標識。任何時候當你使用非相對地址從一行跳到另一行時,編輯器會將你原先的行址標識起來。(“非相對地址”指不是用當前行與原來行之間的間隔行數來表示的地址)

     $
     /the cat/
     358
     ?glossary? +7
     'b

都是非相對行址,如果你使用這些地址在行之間移動,編輯器會標識你在移動之前的所在行以便將來使用。如果你要回到那一行只需輸入兩個連續的半形單引號:

     ''

理論上,這個地址可以做為一個行模式地址與行模式命令一起使用。但當你由於誤操作而移動到檔案中的其他位置時,很難肯定你上一次使用非相對地址移動後保留的行標識是否未受影響――除非你對這個編輯器很熟悉。

對上面的各種方式表示的地址進行修改有兩種方法。簡單一點的方法是為地址加上偏移量,用加號(+)或減號(-)來為地址增加或減少一定數目的行數。規則是地址後的每個加號都指示編輯器在當前檔案的指定地址處下移一行,而減號則相反。依這一規則下面的三個地地址表示的是同一行。

     35
     37 --
     30 +++++

你可能不想用數數的方式來修改行號表示的地址,除非你的數學確實很糟希望編輯器能代你來進行加減運算。但這種數數方式表示的偏移量能與所有的行模式地址一起使用,但最經常的是在搜尋式樣中使用。幸好,這些加號和減號也有簡寫形式。一個加號或減號緊跟著一個數“n”(一位數或多位數)與“n”個加號或減號表示的是一樣的偏移,因此以下的兩個地址是一樣的:

     /^register long/ ++++
     /^register long/ +4

注意第二個例子中的“4”表示的並不是“行號4”,它只有單獨出現時才作為一個地址。在加減號後的數表示的是從前面指定的地址處(上面的例子中這個地址是“/^register long/”)向下或向上移動的數目(如果前面沒有指定的地址則從當前行開始算)。

還要注意這是行模式命令中少數不能插入空格的情況之一。加減號與數字間不能有空格,不然編輯器會在無提示的情況下對行――肯定不是你要的那幾行,進行操作。

第二種風格的地址修改方法可在進行一些複雜的搜尋時使用。假設你想向下定位某以“WARNING!”開頭的行並刪除該行,但有從當前行以下有多行是以“WARNING!”開頭,你要找的第二個符合條件的行。可以使用下面的任一命令:

     /^WARNING!/ ; /^WARNING!/ delete
     /^WARNING!/ ; // delete

兩個搜尋式樣中的分號(;)告訴編輯器先用一般的方式找到第一個搜尋式樣的位置,然後從那個位置開始搜尋第二個式樣。在上面的情況中,第一個搜尋式樣先找到當前行以下以“WARNING!”開頭的第一行,然後第二個搜尋式樣指示編輯器繼續找下一個(也就是第二個)符合條件的行。

分號兩邊的式樣都可以獨立作為一個有效的地址。很重要的一點是上面的命令雖然將兩個搜尋式樣結合使用,卻並不是讓編輯器刪除兩行。分號在這裡的作用是讓第一個式樣成為一個停靠站,編輯器從匹配第一個式樣的行開始搜尋匹配第二個式樣的行,並只刪除第二個式樣所匹配的行。簡言之,這個看上去像表示兩個行的兩個地址實際上是一個地址用以指代某一行。(這並不是這個編輯器的官方文件的說法,但在這一點上官方文件顯然是錯的。)

但好戲才剛要上場呢。沒有人限制說你只能使用兩個地址。我曾經一次用完十個地址來定位某一行,當然這些地址都要用分號隔開。看這個例子:

     ?^Chapter 3$? ; /^Bibliography$/ ; /^Spinoza/ ; /Monads/

將會找到“Spinoza”(斯賓諾莎)的作品中第一部標題中包含“Monads”的著作。編輯器先找到“Chapter 3”(第三章)的“Bibliography”(參考書目)然後找“Spinoza”所在行,並從該行開始向下找包含“Monads”的行。

同樣在分號分隔的地址串中也沒人限制說只能使用搜尋式樣形式的地址。如果你想找到第462行後的第一個包含詞“union”的行,輸入:

     462 ; //

就能把你帶到那行了。並且其中的任何地址都能使用數字偏移,所以:

     462 +137 ; /register int/ ---

也是有效的地址串。

但是不幸的是使用分號分隔的地址串仍有兩個限制。較次要的一個問題是隻有地址串後面的命令能接受第0行作為其地址時,才能在地址串中使用“行號零”。即,除非命令能在第0行使用,不然就算你的地址串由0行開始後又透過附加的地址指示對其他的行進行操作也不行。

     0 ; /Spinoza/ +++ ; /Kant/ delete

這個用以確保搜尋能找到檔案中的第一個“Spinoza”的地址串看上去挺好,但實際執行下去會出現非法地址的“錯誤資訊”。

較主要的問題是:在地址串中用分號隔開的每個地址所表示的在檔案中的位置都必須比前一個地址更靠後。(“地址表示的在檔案中的位置”指在加上偏移量後地址所指代的行的位置。)地址表示的檔案中的位置不能相對分號分隔的上個地址更靠前(即更接近檔案頂部)。

但這不意味著你不能在地址串中使用往回的搜尋式樣(即使用“?”做為式樣的分隔符)。地址串中的第一個地址使用往回搜尋當然是沒問題的。而接下來的地址,只有當你確定使用回搜式樣後實際找到的行要比前一地址更靠後時才能使用回搜的式樣(做為地址)。比如在你知道某個特定的回搜必須在繞回到檔案底部繼續搜尋才能找到匹配的行時就可以使用回搜式樣。一般是這種情形:

     1 ; ?Spinoza? ; /Hegel/ yank

在第1行回搜意味著搜尋將繞回到檔案底部繼續,這就保證了所複製(譯者:“yank”命令的作用就是複製行)的包含“Hegel”的行必定是在檔案中的最後一個包含“Spinoza”的行之後。

還有一種可在地址串中使用回搜的情況就是在回搜式樣後加上偏移量。不過只有在你確定加上偏移量後指代的行在檔案中的位置要比上一個地址表示的行更靠後時才能使用回搜。因此如果我想要確定第八章(“Chapter 8”)中第一次出現“Hegel”的位置距第七章(“Chapter 7”)中最後一次提到“Hegel”的行至少有120行的距離時,我可以輸入:

     /^Chapter 8$/ ; ?Hegel? +119 ; //

如果一個使用上面這個地址的命令出現了非法地址的“錯誤資訊”時,我就可以確定第七章最後一次提到Hegel的行距該章結尾還有120行以上的距離,這樣我就可以知道第八章第一次出現他名字的位置正是我要找的。在這個例子中:

     /^Chapter 8$/ ; /Hegel/

就是我的命令所需要的地址。

使用往前搜尋或者說向下搜尋的情形與上面說的那些內容都差不多。向下搜尋時可以使用負偏移只要使用負偏移後位置不會移到前一個地址表示的位置之上就行。但即使沒有使用偏移或使用正偏移,迴繞搜尋也可能找到一比前面的地址更靠前的位置從而使向下搜尋失敗。




定位一段文字

兩個地址也能用來表示一段文字。當兩個地址用逗號隔開時與分號分隔的地址有著完全不同的意義。

人們經常需要對一些連續的行使用行模式命令。比如你可能需要將一段文字從一個地方移到另一個地方。這時你可以給出該段文字第一行的地址,接著給出該段文字最後一行的地址,兩個地址用逗號隔開。以下命令:

14 , 17 delete

會將第14、15、16、17行刪除。使用多於兩個的用逗號分隔的地址是無意義的。如果你忽略了這點並使用了三個或三個以上的逗號分隔的地址則:編輯器使用前兩個地址並忽略其餘的。

任何行模式地址都能與逗號一起使用。下面例子中的地址用法都是正確的:

     'd , /^struct/
     257 , .
     ?^Chapter 9$? , $

當命令與第一個例子中的地址段一起使用時,編輯器會找到你已用字母“d”標識過的行做為地址段中的第一行,並從該行開始逐行向下施加命令直到找到第一個以“struct”開頭的行(包括這行)為止。第二個地址段的範圍是從257行到當前行。第三個地址段先回搜到上一個只包含“Chapter 9”的行,從該行到檔案中的最後一行就是這個地址段表示的範圍。

這個技巧同樣有限制。主要的限制是逗號後的(加上偏移量後的)地址必須比前一個地址的位置更靠檔案末尾。有效的行範圍中第二個地址必須是在第一個地址表示的行之後

     57 , 188 delete

是有效的命令,而類似的命令:

     188 , 57 delete

只會製造出錯資訊。(如果兩個地址正好指代的是同一行時命令也能正常執行。命令“默默地”對指定的那行進行操作。)

當使用的行模式地址越來越複雜時,你可能會碰到第二個地址先於第一個地址的出錯資訊――而你事先沒料想到地址可能會有任何問題。這不是什麼丟臉的事,解決的辦法也很簡單。在你仔細檢查過地址並確定那些地址就是你要的地址時,只要交換一下兩個地址的次序就行了。即,如果:

     642 , /in Table 23/ delete

出錯了,錯誤資訊提示行的次序錯誤時:

     /in Table 23/ , 642 delete

就能解決那個問題了。

最後一個限制是當你在逗號兩邊使用搜尋式樣時,第二個搜尋與第一個搜尋一樣是從當前行開始而不是從第一個搜尋找到的行開始搜尋。這個限制有個迂迴的解決辦法,這個辦法需要將一個或多個分號與逗號結合使用。

行模式下分號分隔的地址串的用法與單個地址一樣,任何的單個地址都可以用地址串來代替。一個非常實用的技巧是在逗號的兩邊使用地址串,用以精確的定位行範圍。我們說過分號分隔的地址串實際上表示的只是一行的地址,因此地址串也可以用作文字段的開始行或結束行。比如,在下面的命令中:

     /^INDEX$/ ; /^Xerxes/ , $ write tailfile
     ?^PREFACE$? ; /^My 7th point/ , ?^PREFACE$? ; /^In summary/ -- delete

第一條命令將索引(index)的後半部分寫入到一個新的檔案中。第二條命令用來將緒論(PREFACE)中的某一節刪除。

這個技巧為上面說的限制――即第二個搜尋的起點問題,提供瞭解決方案。如果你想要逗號右邊的搜尋從前面搜尋到的行開始,那就在你原來的第二個搜尋式樣(即逗號右邊的搜尋式樣)前面加上第一個搜尋式樣並用分號分隔,例如:

     ?Stradivarius? , ?Stradivarius? ; /Guarnerius/
     ?Stradivarius? , ?? ; /Guarnerius/

考慮到行模式下的地址串不能向上移動,我最好解釋一下當分號與逗號一起使用(就像上面的例子)這些限制的工作機制。除了第一個地址外分號隔開的一系列的地址相對前一個地址都必須更靠近檔案底部(不能向上移動或回搜)。但第二個分號分隔的地址串的開始地址在檔案中的位置卻可以先於第一個地址串(逗號前的地址串)中的任一地址。也就是這個“單向計數器”在遇到逗號後就重置了。在逗號兩邊使用分號分隔的地址串只要求第二個地址串的最終“著陸點”(即地址串最後確定的行,我們說過地址串中雖有多個地址但實際上表示的只是一行的地址)比第一個地址串的“著陸點”更靠近檔案底部就行了,中間的各個地址的相對位置並不影響逗號的使用。為了講清楚點,我們看兩個奇怪的例子,這兩個例子沒什麼實用價值但很能說明問題。

     125 ; 176 ; 221 , 32 ; 67 ; 240

上面的地址似乎是無效的因為出現了地址回移(向上移動)的情況――從行221到行32,事實上這卻是個完全合法的地址。因為回移是出現在逗號後,這是規則允許的。但:

     125 ; 176 ; 221 , 32 ; 67 ; 218

卻會出現“錯誤資訊”,因為第一個地址串的“著陸點”(行221),在第二個地址串的“著陸點”(行218),之後。

關於預設地址。我已經說過大多數能使用單個地址的行模式命令有一個“預設”的內建地址,當你沒為命令提供地址時編輯器就使用預設的地址。不同的命令有不同的預設地址,可能是當前行,可能是當前行和下一行,可能是最後一行或者是整個檔案。

逗號分隔符也有自己的預設地址。無論逗號與什麼命令一起使用,這個預設地址都是一樣的,並且這個預設地址會覆蓋命令自身的預設地址。如果你在命令前使用了逗號但沒提供逗號左邊的地址,預設的左邊地址是當前行。同樣的如果你沒提供逗號右邊的地址,預設的右邊的地址也是當前行。你還可以將逗號兩邊的地址都留空,這時兩邊的預設地址都是當前行:表示預設行範圍是“從當前行到當前行”,其實也就是讓命令對當前行進行操作。因此下面的每條命令:

     .     write >> goodlines
     . , . write >> goodlines
       , . write >> goodlines
     . ,   write >> goodlines
       ,   write >> goodlines

做的事兒都是一樣的:在當前編輯檔案中匯出當前行並新增到名為“goodlines”的檔案末尾。

最後,還有一個用來表示某個逗號分隔地址段的特殊符號――百分號(%)。這個符號與“1,$”的表示的範圍是一樣的,都用來指代整個檔案。





下一個: next-installment,
上一個: text-section,
上層: line-mode-addresses

親身實踐

在你遇到需要複雜的行模式地址的編輯情況之前,這兒有些問題可讓你先鍛鍊一下自己。這裡的每個問題都提供了一個相應的“參考答案”。
怎樣讓編輯器找到檔案中最後一次出現單詞“EXPORT”的行,並刪除該行?如果你知道從哪開始搜尋的話,答案就相當明瞭了。

假設你想要找到並刪除檔案中“EXPORT”第一次出現時所在的行,這行有可能正好是第一行。你不能從第0行開始搜尋因為刪除命令不接受虛構的地址――第零行。當你使用地址串“$ ; /EXPORT/”來進行繞回的向下搜尋時,出現了錯誤資訊:搜尋式樣找到的行要先於做為第一個地址的“$”找到的行――就跟你設想的一樣。怎樣才能讓編輯器找到並刪掉這行呢?解決這個問題需要一點創造性。

在你使用地址“?abc? , /xyz/”時,它包括了匹配式樣的兩行(分別是匹配“abc”和“xyz”的行),及兩行之間的所有行。怎樣才能指定範圍為兩行之間的所有行,但不包括那兩行自身(在這個例子中就是匹配“abc”和“xyz”的兩行)呢?答案可能會比你想像的要來得簡單。





下一篇

在下一篇我們會講解“Global”命令,相對這一章講的讓人發睏的各種地址型別而言下一篇的內容會精彩得多。並且讓你有機會能使用剛講過的這些不同的地址型別,我也會涉及到一些行模式命令尤其是那些有著你所未料想到的用法的命令。

Appendix A 答案

這裡是上面習題的答案。用uudecode開啟看答案是什麼。

begin 644 viex2_ans
M5FDO17BQX+RMQO>CK+7:MO[5PJ.ZLLZ_O+3PL+@-"@T*#0JAL$584$]25*&Q
MSLK,XK+.O[RT+"X#0H-"LKDR.NCN@T*#0HQ(#L@/T584$]25#@9&5L971E
M#0H-"K[-T-#!RZ&CU-K.Q+S^UM"UQ+7:TKO0T,JYT.[V,O1HZS$W,BWL:/5
MTK6]M<2UVM*[N/:P_+JLH;!%6%!/4E2AL;7$T-"^S"K[/U,J^U^ZZ]*[
MT-"CK-7BN/;#_,'NL;[)[=/KSM+#Q[7$SLK,XL[>N=BCK+6KRL?4VLOUK30
MT+KSU^ZZ]*[T-"SR^S=/)SL2_K7$M=K2N]#0OZK*O,'+H:,-"@T*#0JA
ML+*[L/S`J,J]T?G0T*&QSLK,XK+.O[RT+"X#0H-"M:[TJK4VK:ZNL7'L+7$
MM=C6M[KSS.W2N[CVH;"T[K%H;&CK-3:MKJZQ;KSM<2UV-:WNO/,[=*[N/:A
ML+SUNL6AL:.LOLW/=7BT?FCN@T*#0H_86)C/R`K("P@+WAY>B@+0T*#0K5
MXL&]N/;&J]+&P;_(P[$L;ZWMLZGS_+.Q+&^MLZUQ-;0O.2^V*CHZS(P[$
ML;ZVSK7$P;VVR[CWU]3/M;0O.32QK:OP3*
MO='YM<30T,W1P.O#_,'NU_?3P[7$SL2QOK>VSJ>AHZ.HU-JQOL#]UM#!O;CV
MM=C6M[7$R]'+][>]S_*RNK'UMBUXZ.LUMC2JK7$RL?'L-*[N/:UV-:WNO/#
MYK'8T.O*Q]7]QJO2QJ.LMOBVNKK%NO.QV-#KRL>XNL:KTL:RQ<3
[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1040213/,如需轉載,請註明出處,否則將追究法律責任。

相關文章