第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于后续版本,但有一些区别。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助 支持 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<>”,但您可以使用任何字符作为分隔符。