強大的字串處理能力常常是直譯式程式語言的指標性特色,例如,Perl、Python、Ruby都是如此,當然Tcl也不例外。Tcl提供了兩種方法讓你處理字串,一種是普通的字串處理方法,另一種則是以正規表示式為基礎的字串處理。這一篇文章著重在前者的說明,至於後者的說明我打算讓它出現在進階篇的內容。
9.1 字串串接
字串串接是很常使用的功能,例如你有兩個字串然後想要把它們組合成一個更大的字串,這時就會用到串接的功能。append命令供了這樣的功能,它可以把多個字串逐一串接在指定的變數後面,append的語法如下:append varName ?string1 string2 .... stringN?
append命令把參數string1~stringN串接在varName指定的變數尾巴,然後回傳串接後的結果。varName必需是變數的名字,如果該變數不存在append會自動建立它。 程式範例:
程式輸出:
Hello Tcl Hello Tcl/Tk!
9.2 計算字串長度
Tcl的string命令包含了一整套的字串處理功能,例如:計算長度、字串搜尋、字串取代、取出字串片段....等。接下來就先以計算字串長度開始說明string命令的用法。Tcl可以用兩種計算字串的長度,以下是這兩種方法的說明:
□ 計算位元組數
string bytelength string1
若string命令的第一個參數為字串bytelength,string命令會回傳string1所佔用的位元組數,string1即為要計算的目標字串。注意!!在這一章的內容string1會一直出現,如果沒有特別說明,這個參數都表示為要操作的目標字串。
□ 計算字元數
string length string1
若string命令的第一個參數為字串length,string命令會回傳string1的字元數。例如:
程式輸出:
6 9 6 3
為了方便說明,接下來的內容我會把string及它的第一個參數念做一起。例如,如果我說string length,實際上是指string命令後面的第一個參數是length。
§ 中文字的位元組數
在我的執行環境裡,系統預設的編碼是UTF-8,所以一個中文字佔用了3個byte。
§ 關於string命令
為了做到一個命令實現多種功能,string命令使用了第1個參數的值來決定真正該做的事,例如第一個參數是length就表示要算字串的長度、若是index就表示要取字串中的單字。像這種一個命令多種功能的做法被普遍的使用在Tcl裡面,其目的是希望讓同一性質的命令有統一的操作方法,像這樣的命令使用方法以後我們會常常看到,請大家慢慢習慣它。
9.3 截取字串內容
截取字串是撰寫解析器(Parser)常用的功能,例如,解析網頁的HTML找出所有的超連結標籤,或是解析網路協定封包取出特定欄位值,都會使用到這個功能。一般來說常用的字串截取需求有兩個,第一個是要可以一次取出一個字元,另一個是要可以一次取一個範圍的字串子集合,當然這兩個功能string命令都有提供。□ 截取單一字元
string index string1 charIndex
string index回傳string1中索引位置為charIndex的字元。charIndex必需為零以上的整數或是end。end可以用來表示字串中最後一個字元的索引值。
□ 截取子字串
string range string1 first last
string range回傳string1中索引位置first到last間的子字串,而且包含first及last本身。其中first及last必需為零以上的整數或是end。end可以用來表示字串中最後一個字元的索引值。
string命令有許多功能都會使用到索引位置。接下來的內容如果沒有特別說明,就表示它們都是套用以下的規則:
- 索引位置即必需為零以上的整數。
- 索引位置可以使用end表示字串中最後一個字的索引位置。
以下是string index及string range的使用範例:
程式輸出:
1 家 bc12 Hi!
9.4 字串轉換
字串轉換包含英文字母大小寫轉換、剔除字元及字串取代等功能。這些功能時常會出現在搜尋文件或是格式化文字內容的程式裡。string當然也有提供這些功能,使用它們就可以輕鬆的應對各種字串轉換的狀況。□ 轉換大小寫
string tolower string1 ?first? ?last?
string tolower把string1中索引位置first到last間的大寫英文字母轉換為小寫,然後回傳新的字串,而且包含first及last本身。若first及last沒有指定就把整個字串轉換為小寫字母。
string toupper string1 ?first? ?last?
toupper的使用方法如同tolower一樣,只是改成把string1中的小寫字母轉換為大寫。
string totitle string1 ?first? ?last?
totitle的使用方法如同tolower一樣,只是改成把string1中的第一個字母轉為大寫其它則轉為小寫。
轉換大小寫的範例如下:
程式輸出:
abcabc ABCABC Hello!! tcl/tk 英文字母HELLO夾中文字一樣沒問題
□ 剔除字串
如果你想要剔除字串前後某些不想要的字元,例如:空白。string命令也提供了數個功能,讓你可以處理這些工作,它們的語法如下:string trim string1 ?chars?
string trim把string1左邊及右邊有包含在chars中的字元刪除,然後回傳新的字串。若chars不指定預設是刪除Unicode的空白字元 ex. \t \r \n \s。
string trimleft string1 ?chars?
如同trim只是改成刪除string1左邊含有chars的字元。
string trimright string1 ?chars?
如同trim只是改成刪除string1右邊含有chars的字元。
剔除前後字串的程式範例:
程式輸出:
abc abc abc 文字abc 123 中中中文文文字字字 字abc 123 中中中文文文字字字 abc 123
雖然上方的第1及第2行輸出雖然看起來一樣,但事實上第2行輸出的後面的空白並沒有被刪除。
□ 字串取代
字串取代算是文字編輯器裡必備的功能之一,例如:Windows的記事本就有提供取代功能。一般來說取代時常配合搜尋來使用,常見的動作是:先透過搜尋找到想要被取代的位置,然後再用取代的功能來把原來的字串換掉。字串取代真的滿重要的,如果不會的話,像文字編輯器一類的程式就寫不出來了。以下是關於字串取代的語法。string map ?-nocase? mapping string1
string map會把mapping當成是對照表去替換string1的內容,然後回傳替換後的新字串。若指定-nocase表示要把英文字母的大小寫視為一樣。mapping必需是一個清單而且項目的總數量一定要是偶數倍。如此一來string命令會把mapping中單數的項目當成是要被換掉的字串,雙數項目當成是要替換的結果。範示如下:
程式輸出:
Apple大家吃,好書大家看 蘋果大家吃,好書大家看
接下來是一個比較簡單的取代功能,它可以把字串裡特定範圍的內容換成新的內容,事實上我比較愛用string map。
string replace string1 first last ?newstring?
string replace把string1索引位置first到last間的子字串替換為newstring,然後回傳新的字串,而且包含first及last本身。若沒有給予newstring預設取代為空字串。
程式範例:
程式輸出:
前面8個字不見了!!
□ 字串重製
有時候我們會想要讓某些字串重複N次,在Tcl裡可以用下面的方法。string repeat string1 countstring repeat命令把string1的值重覆count次,然後回傳新的字串,count必需為零以上的整數。
程式範例:
程式輸出:
tcltcltcltcltcl
□ 字串轉清單
最後要介紹一個很常使用的字串轉換功能,它可以利用字串裡的某些字元來把字串切割成清單的項目,簡單的說這是一種字串轉換為清單的功能。split string1 ?splitChars?
split命令以splitChars裡的字元當項目分隔來切割string1,然後以清單的方式回傳切割後的結果。若不指定splitChars預設會以所以的Unicode空白字元來做分隔字元。
程式範例:
程式輸出:
www google com tw
9.5 字串搜尋
字串搜尋時常會伴隨著字串截取使用。常見的程式動作是:先透過搜尋由較大的字串找出符合的字串片段,然後再透過字串截取來得到真正想要的內容。string命令對字串搜尋主要提供了4個功能,除了常見的「找第一個」及「找最後一個」之外,也提供了「找單字開頭」及「找單字結尾」的功能。□ 找第一個及最後一個
string first string1 string2 ?startIndex?
string first由索引位置startIndex的位置開始尋找string1出現在string2的位置,若找到的話回傳第一次找到的開始索引位置,否則回傳-1。若startIndex沒有指定,預設會從頭開始找。
string last string1 string2 ?lastIndex?
如同string first的用法,只是改成找最後一個符合的位置。string會由索引位置lastIndex開始往前找。若lastIndex沒有指定,預設會從最後一個字往前找。
程式範例:
程式輸出:
2 12 12 2
□ 尋找單字的開頭及結尾
這是其它程式語言比較少見的功能,很幸運的Tcl提供了。透過下面的命令,你可以很方便的找出字串裡某個英文單字的開頭或結尾:string wordend string1 charIndex
string wordend會由索引位置charIndex開始尋找單字的結尾,若找到的話回傳第一次找到的索引位置,否則回傳0。
string wordstart string charIndex
如同string wordend的用法,只是改為找單字的開頭。
程式範例:
程式輸出:
-powerfully - 中文行得通?
程式的第4行特別在取出字串範圍的前後加上一根短線,以方便觀查。另外,在第1行的輸出裡,其實wordend找到的位置包含了空白字元,也就是單字結尾的下一個字元。
9.6 字串比對
字串比對常常發生在if或迴圈的條件式裡,在條件式裡非常直覺的會讓人想用 「==」及「!=」這兩個運算方法,事實上這兩個運算方法在某些情況下會有一些問題。接下來的字串比對方法可以避開這些問題,也適用於較複雜的比對情況。□ 字串比對語法
string compare ?-nocase? ?-length len? string1 string2
string compare以unicode字碼的方式逐一比較string1及string2包含的字元,如果string1大於string2回傳1,如果回傳0表示兩個字串相同,如果傳回-1表示string1小於string2。 若指定-nocase表示比對時不分大小寫。若指定-length參數的話,len用來決定要比對的長度,預設的比對長度是string1及string2中較短的字串。
string equal ?-nocase? ?length len? string1 string2如同string compare的字法,只是改為如果string1完全等於string2回傳1,否則回傳0。
程式範例:
程式輸出:
-1 0 0 1
if命令在下面樣的情況下,可能會輸出不是你期望的結果,原來你是想要比較0x0a及10這兩個字串,但因為0x0a同樣也是合法的16進制數值表示法,所以0X0a就被當成是16進制的10,結果判斷式成立了。
§ string compare及==的差異
注意哦!!string compare是以unicode字碼的方式逐一比較,但==的運算符號會解釋字面的意義,再比較。例如,對==運算符號來說6、06及0x06的意義都是數值的6,所以上一個例子會成立,但若以string compare逐字碼比較,上一個例子就不會成立了。再次提醒,別忘了if是用和expr同樣的方式求值它的運算式。
□ 判斷字串類別
有時候你會想知道某個字串,到底屬於那一種類型的資料,整數、字母或標點符號? 這時候你可以使用下面的命令來判別字串的類型:string is class ?-strict? ?-failindex varname? string1
string is逐一字元判斷string1是否符合class指定的類別。如果不指定-strict參數string1為空字串時會無條件回傳1,如果指定的話會回傳0。如果指定-failindex參數,varname可以用來指定一個變數名稱,當判斷類型不成立時,這個變數用來儲存第一個判斷失敗的位置,位置從0開始。以下是可以用來判斷的類別:
alnum | 任何Unicode的英文字母和數字 |
alpha | 任何Unicode英文字母 |
ascii | 任何ascii碼127以下的符號 |
boolean | 可以是1、0、true、false (不分大小寫) |
control | 任何Unicode的控制字元 |
digit | 包含Unicode數字[0-9] |
double | Tcl認可的double數值 (跟作業系統平台有關) |
false | 0、false (不分大小寫) |
graph | 任何Unicode可視字元,不包含空白字元 |
integer | Tcl認可的integer數值 (跟作業系統平台有關) |
lower | 任何Unicode小寫的英文字母 |
任何Unicode可視字元,包含空白字元 | |
punct | 任何Unicode的標點符號 |
space | 任何Unicode的空白字元 |
true | 1、true (不分大小寫) |
upper | 任何Unicode大寫英文字母 |
wordchar | 任何Unicode英文字母、數字、連接字元 ex.底線 |
xdigit | 任何16進制的數字[0-9A-Fa-f] |
程式範例:
程式輸出:
1 0
□ 進階比對功能
接下來的string match提供了比較強大的比對功能,它可以讓你使用Unix glob-style的方式來比對字串是否符合某個pattern,它的說明如下:string match ?-nocase? pattern string1
string match使用Unix glob-style的方式比對pattern及string1,若string1符合pattern就回傳1,否則回傳0。如果指定-nocase,表示比對字串時不分大小寫。pattern簡單的說是一些關鍵字及特殊比對字元組成的字串,以下是pattern字可用的特殊比對字元:
* | 符合任意長度的字元 |
? | 符合任意一個字元 |
[chars] | 符合chars集合內的任一字元 |
\x | 用來跳脫特殊字元 *?[]\ |
control | 任何Unicode的控制字元 |
digit | 包含Unicode數字[0-9] |
double | Tcl認可的double數值 (跟作業系統平台有關) |
false | 0、false (不分大小寫) |
graph | 任何Unicode可視字元,不包含空白字元 |
integer | Tcl認可的integer數值 (跟作業系統平台有關) |
lower | 任何Unicode小寫的英文字母 |
程式範例:
特別注意!! 第2行的中括號請用反斜線來取消代換或改成用大括號包夾,否則會被當成子命令並執行代換的動作。
程式輸出:
1 1
按右上方的「#」號切換側邊欄