如果一個字串使用空白字元將資料隔成多個項目,例如:"apple book car duck",像這種格式的字串內容,Tcl稱之為清單(List)。對於清單式的資料Tcl提供了很多方便的操作命令,讓你可以快速的排序、搜尋及取出清單中項目。本篇文章介紹Tcl裡常用的清單命令並示範它們的使用方法。
6.1 建立清單
前面有說到清單是以空白當分隔的字串,所以你還是可以把清單當成是字串,只是Tcl對這種清單式的字串提供了額外的功能,讓你可以很容易的以項目為單位來操作這種資料,而不是以字元為單位。下面的程式展示了三種建立清單的方法,第一種使用雙引號來包夾字串,它總共隔出了3個項目。第2種改採用大括號來包夾字串,然後隔出了4個項目。最後一種使用list命令及命令代換來建立清單。原則上你可以任意的使用上面的三種方法來建立清單,但要注意使用大括號會取消代換的功能,所以如果你有變數需要當成清單的項目,請考慮使用另外兩種方法,不然變數的內容不會被代換。例如下面的$var不會被代換。
如果項目本身也有包含空白,請用雙引號或大括號包夾項目,例如:
最後請特別注意,下面的程式是一個常見的錯誤,第2行你可能預期list1包含了4個項目,但其實包含了5個。因為根據變數代換的原則,第2行的$var被代換後,字串的結果是"pen pencil eraser pencil case",所以list1事實上包含了5個項目。
以下是比較正確的方法:
§ 關於清單
雖然上述的三種方法都可以用來建立清單,而且使用上的感覺也都一樣,但是實際上使用list命令建立的清單,Tcl內部會以不一樣的方法處理。所以如果你可以確定新建立的清單,不會被自己拿來當字串使用,請盡可能使用list命令,因為這樣會比較有效率。 以前我都叫清單為「串列」因為這樣比較符合Tcl內部的資料結構,不過後來覺得就字面上來說「清單」好像也滿貼切的,所以就都用清單了。
6.2 取出清單中的項目
Tcl提供了「索引」及「範圍」兩種方法來取出清單中的項目,「索引」的方法可以用來取出1個項目,而「範圍」的方法則可以取出項目的子集合。6.2.1 取出清單中的單一項目
lindex命令可以用來取出清單中特定的項目,它的語法如下:lindex list ?index?
lindex執行後回傳符合索引位置的項目。其中list是要操作的清單,index是整數的索引位置。如果不指定index的話會回傳所有的項目。程式6-1示範lindex常見的用法。程式的第1行先建立了一個3個項目清單,第2行用lindex命令取出$list中索引值是0的項目。注意哦!!清單的索引值由0開始算,所以取出來的項目是pen。第3行取出索引為2的項目,所以輸出是eraser,第4行說明lindex允許使用end來表示最後一個索引值,第5行則是由最後一個索引值往前算2個,所以是倒數第3個項目。
程式輸出:
pen eraser eraser pen
6.2.2 取出清單的子集合
lrange命令可以用來取出清單中特定範圍的項目群,它的語法如下:lrange list first last
lrange執行後會回傳取出一個範圍的項目群,然後回傳一個新的清單。list是要操作的清單,first是要取出的開始位置,last是要取出的結束位置。如同index命令first及last必需是零以上的整數,而且可以使用end來表示最後一個項目的索引值。如下是它的使用範例:
程式輸出:
apple book cute duck duck eat fruit green apple book cute duck eat fruit green cute duck eat eat fruit green
6.3 把項目加到已存在的清單
如果要把新的項目加入已存在的清單,可以使用linsert及lappend這兩個命令。lappend可以把新的項目附加在清單的尾巴。而linsert可以把新的項目插入清單的任意位置。6.3.1 附加項目至清單的尾巴
lappend可以用來把新的項目附加至清單變數的尾巴,lappend的語法如下:lappend varName ?value value value ...?
lappend把value的值逐一附加在varName的尾巴,最後回傳附加後的結果。varName必需是一個變數的名稱,如果變數不存在lappend會自動建立。如果沒有指定任何value則不附加任何項目。以下是lappend的使用方法:
程式輸出如下:
pen pencil pen pencil eraser {pencil case}
6.3.2 插入項目至清單的任意位置
lappend有兩個特點:- 只能用在清單變數上。
- 只能把新的項目串接在清單的最尾巴。
linsert和lappend不同,它可以把新的項目插入到清單的任意位置,下面是它的語法:
linsert list index element ?element element ...?
linsert執行後把項目element逐一插入清單list索引值為index的位置,然後回傳插入後新的清單。請注意linsert是對清單的值操作而不是對清單變數操作,所以它不會修改到變數的內容。以下是linsert示範用法:
程式輸出如下:
pen pen2 pencil eraser pen pencil eraser pen pen2 pen3 pencil eraser
linsert同樣可以使用end來表示最後一個項目的索引值。特別注意!! 執行linsert並不會修改到清單變數。所以從程式第3行的輸出可以發現,$list1並沒有因為第2行的程式而被改變。第4行把linsert執行的結果重新設定給list1變數,所以第5行的輸出可以看出list1變數被改變了。
6.4 其它常用的清單操作命令
接下來我們要繼續測試幾個常用的清單命令,包含計算項目數量用的llength、排序用的lsort及搜尋用的lsearch。6.4.1 計算清單包含的項目數量
如果你想知道清單到底包含幾個項目可以使用如下的llength命令:程式輸出如下:
3
6.4.2 排序清單中的項目
lsort排序清單中所有的項目,並回傳排序後新的清單,它的語法如下:lsort ?options? list
list是要被排序的清單,options欄位用來調整排序時的方法,以下是options欄位常用的參數:
表6-1 lsort可用的選項
-ascii | 使用Unicode內部的編碼來排序,這是預設的方法。 |
-dictionary | 使用像字典一樣的排序方式。 |
-integer | 把所有清單中的項目轉換為整數排序。 |
-real | 把所有清單中的項目轉換為浮點數排序。 |
-command command | 使用自己提供的命令來比較清單的內容,lsort會不斷執行command命令並把2個項目傳入,如果第1個項目大於第2個command需要回傳1,如果2個項目相同command需要回傳0,如果第1個項目小於第2個項目command要回傳-1。 |
-increasing | 排序的結果使用遞增的方式,這是預設的方法。 |
-decreasing | 排序的結果使用遞減的方式。 |
-index index1 | 如果指定這個參數,每一個項目的內容都會被當成是子清單,然後lsort會對每個子清單索引位置為index1的項目做排序。 |
-nocase | 排序時把英文字母大小寫當作一樣。 |
-unique | 找出清單裡最長且不重複的子清單集合。 |
它的示範如下:
程式輸出如下:
apple book cute duck eat fruit green green fruit eat duck cute book apple a1 a10 a100 1 2 3 4 5 11 1 2 3 4
6.4.3 搜尋清單中的項目
lsearch命令可以用來搜尋清單中符合關鍵字的項目,並回傳第一個找到的索引位置。它的語法如下:lsearch ?options? list pattern
lsearch傳回清單list中第一個符合pattern的項目索引值,如果找不到符合的項目就回傳-1。其中list是目標要搜尋的清單,pattern是要搜尋的關鍵字,options可以用來指定搜尋時的方法。以下是options欄位常用的參數:
表6-2 lsearch可用的選項
-all | 如果指定這個參數lsearch會找出所有符合索引的位置,並把位置以清單的型式回傳。 |
-ascii | 先把清單項目使用Unicode內部的編碼來排序,然後再執行搜尋動作。 |
-decreasing | 先把清單做遞減排序,然後再執行搜尋動作。 |
-dictionary | 先把清單做字典方式排序,然後再執行搜尋動作。 |
-exact | 使用精確比對。 |
-glob | 使用unix glob方式的比對,這是預設值。 |
-increasing | 先把l清單做遞增排序,然後再執行搜尋動作。 |
-inline | 回傳時改用符合的項目內容取代符合的項目索引,如果配合-all,會回傳所有符合的項目清單。 |
-integer | 把所有的項目轉成整數來排序,然後再執行搜尋動作。 |
-not | 反相搜尋,找出第一個不符合pattern的項目。 |
-real | 把所有的項目轉成浮點數型態來排序,然後再執行搜尋動作。 |
-regexp | 使用正規表示式比對。 |
-sorte | 讓lserch在搜尋前跳過排序的動作,並使用exact方式比對。 |
-start | 指定啟始的搜尋位置。 |
lsearch示範使用如下:
程式輸出如下:
2 2 5 b35 a20 a20 c47 0 2 5
本章回顧
如果一個字串使用空白字元將字串隔成多個項目,像這種格式的字串內容,Tcl稱之為清單(List)。對於清單式的資料Tcl提供了很多方便的操作命令,讓你可以快速的排序、搜尋及取出清單中項目。建立清單的方法像這樣:常用來操作清單的命令整理如下:
命令 | 說明 |
lappend varName ?value value value ...? | lappend把value的值逐一附加在varName的尾巴,最後回傳附加後的結果。varName必需是一個變數的名稱。 |
lindex list ?index? | lindex取出list索引位置index的項目。 |
insert list index element ?element element ...? | linsert把項目element逐一插入list索引值為index的位置,然後回傳插入後新的清單。 |
lrange list first last | lrange取出list範圍first到last的項目群,然後回傳新的清單。 |
lsearch ?options? list pattern | lsearch傳回list中第一個符合pattern的項目索引值,如果找不到符合的項目就回傳-1。 |
lsort ?options? list | lsort排序list中所有的項目,並回傳排序後新的清單。 |
按右上方的「#」號切換側邊欄