此第一版是為 Lua 5.0 所撰寫。雖然對後續版本仍有很大的相關性,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買本書,您也可以協助 支持 Lua 專案


20.2 – 模式

您可以使用字元類別讓模式更實用。字元類別是模式中的一個項目,可以符合特定集合中的任何字元。例如,類別 %d 符合任何數字。因此,您可以使用模式 '%d%d/%d%d/%d%d%d%d' 來搜尋 dd/mm/yyyy 格式的日期。

    s = "Deadline is 30/05/1999, firm"
    date = "%d%d/%d%d/%d%d%d%d"
    print(string.sub(s, string.find(s, date)))   --> 30/05/1999
下表列出所有字元類別
.所有字元
%a字母
%c控制字元
%d數字
%l小寫字母
%p標點符號字元
%s空白字元
%u大寫字母
%w字母數字字元
%x十六進位數字
%z表示 0 的字元

任何這些類別的大寫版本代表類別的補集。例如,'%A' 代表所有非字母字元

    print(string.gsub("hello, up-down!", "%A", "."))
      --> hello..up.down. 4
4 不是結果字串的一部分。它是 gsub 的第二個結果,即替換的總數。其他會列印 gsub 結果的範例會省略這個計數。)

某些稱為特殊字元的字元在模式中使用時具有特殊意義。特殊字元為

    ( ) . % + - * ? [ ^ $
字元 `%´ 可作為這些特殊字元的跳脫字元。因此,'%.' 符合一個點;'%%' 符合字元 `%´ 本身。您不僅可以使用跳脫字元 `%´ 來處理特殊字元,也可以用於所有其他非字母數字字元。有疑問時,請採取安全做法並加上跳脫字元。

對於 Lua,模式是正規字串。它們沒有特殊處理,並遵循與其他字串相同的規則。僅在函數內將它們解釋為模式,並且僅在這種情況下,`%´ 才作為跳脫字元使用。因此,如果你需要在模式中放入引號,則必須使用與在其他字串中放入引號相同的技術;例如,你可以使用 `\´ 跳脫引號,這是 Lua 的跳脫字元。

字元集 允許你建立自己的字元類別,將不同的類別和單一字元組合在方括號中。例如,字元集 '[%w_]' 匹配字母數字字元和底線,字元集 '[01]' 匹配二進位數字,而字元集 '[%[%]]' 匹配方括號。若要計算文字中的母音數量,你可以寫

    _, nvow = string.gsub(text, "[AEIOUaeiou]", "")
你也可以在字元集中包含字元範圍,方法是寫出範圍的第一個和最後一個字元,並用連字號分隔。你很少需要這個功能,因為大多數有用的範圍已經預先定義;例如,'[0-9]' 寫成 '%d' 時更簡單,'[0-9a-fA-F]' 與 '%x' 相同。但是,如果你需要找到八進位數字,則你可能更喜歡 '[0-7]',而不是明確列舉('[01234567]')。你可以透過在字元集開頭加上 `^´ 來取得其補集:'[^0-7]' 找到任何不是八進位數字的字元,而 '[^\n]' 匹配任何與換行不同的字元。但請記住,你可以使用其大寫版本來否定簡單類別:'%S' 比 '[^%s]' 更簡單。

字元類別遵循 Lua 設定的目前區域設定。因此,類別 '[a-z]' 可能與 '%l' 不同。在適當的區域設定中,後一種形式包含 `ç´ 和 `ã´ 等字母。你應該始終使用後一種形式,除非你有充分的理由不這樣做:它更簡單、更具可移植性,而且效率稍高。

你可以使用重複和選用部分的修飾符讓模式更有用。Lua 中的模式提供四個修飾符

+1 次或多次重複
*0 次或多次重複
-另有 0 次或多次重複
?選用(0 次或 1 次出現)

修飾符 `+´ 匹配原始類別的一個或多個字元。它將始終取得與模式匹配的最長序列。例如,模式 '%a+' 表示一個或多個字母,或一個字

    print(string.gsub("one, and two; and three", "%a+", "word"))
      --> word, word word; word word
模式 '%d+' 匹配一個或多個數字(一個整數)
    i, j = string.find("the number 1298 is even", "%d+")
    print(i,j)   --> 12  15

修飾符 `*´ 類似於 `+´,但它也接受類別字元的零次出現。典型的用法是匹配模式部分之間的選用空格。例如,若要匹配空括號對,例如 ()( ),請使用模式 '%(%s*%)'。(模式 '%s*' 匹配零個或多個空格。括號在模式中具有特殊含義,因此我們必須使用 `%´ 跳脫它們。)另一個範例,模式 '[_%a][_%w]*' 匹配 Lua 程式中的識別碼:一個以字母或底線開頭的序列,後跟零個或多個底線或字母數字字元。

與 `*´ 相似,修飾符 `-´ 也會比對原始類別中零個或多個字元。不過,它不是比對最長的序列,而是比對最短的序列。有時,`*´ 或 `-´ 之間沒有差異,但通常它們會呈現出截然不同的結果。例如,如果你嘗試使用樣式 '[_%a][_%w]-' 尋找識別碼,你只會找到第一個字母,因為 '[_%w]-' 永遠會比對空序列。另一方面,假設你想要在 C 程式中尋找註解。許多人會先嘗試 '/%*.*%*/'(也就是一個 "/*" 後面接著一個任意字元序列,再後面接著一個 "*/",並寫入適當的跳脫字元)。然而,由於 '.*' 會盡可能地擴充,程式中的第一個 "/*" 只會與最後一個 "*/" 關閉

    test = "int x; /* x */  int y; /* y */"
    print(string.gsub(test, "/%*.*%*/", "<COMMENT>"))
      --> int x; <COMMENT>
相反地,樣式 '.-' 會擴充最少必要的數量以找到第一個 "*/",這樣你才能得到想要的結果
    test = "int x; /* x */  int y; /* y */"
    print(string.gsub(test, "/%*.-%*/", "<COMMENT>"))
        --> int x; <COMMENT>  int y; <COMMENT>

最後一個修飾符 `?´ 會比對一個可選字元。舉例來說,假設我們想要在文字中尋找一個整數,其中數字可能包含一個可選符號。樣式 '[+-]?%d+' 可以完成這項工作,比對像 `"-12"`, `"23"`, 和 `"+1009"` 這樣的數字。`[+-]` 是同時比對 `+´ 或 `-´ 符號的字元類別;後面的 `?´ 使得符號成為可選的。

與其他一些系統不同,在 Lua 中,修飾符只能套用於字元類別;沒有辦法將樣式群組在修飾符之下。例如,沒有樣式可以比對一個可選字詞(除非該字詞只有一個字母)。通常你可以使用我們稍後會看到的進階技巧來規避這個限制。

如果一個樣式以 `^´ 開頭,它只會比對主旨字串的開頭。類似地,如果它以 `$´ 結尾,它只會比對主旨字串的結尾。這些標記可以用來限制你找到的樣式,也可以用來錨定樣式。例如,測試

    if string.find(s, "^%d") then ...
檢查字串 `s` 是否以數字開頭,而測試
    if string.find(s, "^[+-]?%d+$") then ...
檢查該字串是否表示一個整數,沒有其他前導或尾隨字元。

樣式中的另一個項目是 '%b',它比對平衡字串。此項目寫作 '%bxy',其中 xy 是任何兩個不同的字元;x 作為開頭字元,y 作為結尾字元。例如,樣式 '%b()' 比對字串中以 `(´ 開頭並以對應的 `)´ 結尾的部分

    print(string.gsub("a (enclosed (in) parentheses) line",
                      "%b()", ""))
      --> a  line
通常,這個樣式用作 '%b()'、'%b[]'、'%b%{%}' 或 '%b<>',但你可以使用任何字元作為分隔符號。