模式教程 |
|
阅读完本教程后,强烈建议您阅读模式手册[1],以便您了解它提供的所有功能。
首先,我们将使用string.find
函数,该函数在字符串中查找模式的第一个出现位置,并返回匹配文本的第一个和最后一个字符的起始和结束索引。
> = string.find('banana', 'an') -- find 1st occurance of 'an' (letters are matched literally) 2 3 > = string.find('banana', 'lua') -- 'lua' will not be found nil
但仅仅匹配文本并不那么有用,因此模式具有字符类的概念。字符类是一种匹配一组字符中之一的模式。例如,.
是一个匹配任何字符的字符类。
> = string.find("abcdefg", 'b..') 2 4
我们现在可以使用这些索引来获取匹配的文本,但有一个更好的方法:string.match
函数。它返回匹配的文本,或者如果未找到模式则返回 nil:(实际上,find 也返回匹配的文本,但它首先返回索引;match 只返回文本)。
> = string.match("abcdefg", 'b..') bcd
模式有一些预定义的类,使用它们作为“%x”,其中“x”是标识类的字母。
> = string.match("foo 123 bar", '%d%d%d') -- %d matches a digit 123 > = string.match("text with an Uppercase letter", '%u') -- %u matches an uppercase letter U
您还可以通过将一组字符括在方括号中来创建自己的类。这将匹配这些字符中的一个。如果方括号内的第一个字符是^
,那么它将匹配不在该组中的字符。
> = string.match("abcd", '[bc][bc]') bc > = string.match("abcd", '[^ad]') b > = string.match("123", '[0-9]') -- you can specify a range of characters using - 1
即使使用字符类,这仍然非常有限,因为我们只能匹配具有固定长度的字符串。为了解决这个问题,模式支持以下四个重复运算符。
*
匹配前一个字符(或类)零次或多次,尽可能多次。
+
匹配前一个字符(或类)一次或多次,尽可能多次。
-
匹配前一个字符(或类)零次或多次,尽可能少次。
?
使前一个字符(或类)可选。
我们将从?
开始,因为它是最简单的。
> = string.match("examples", 'examples?') examples > = string.match("example", 'examples?') example > = string.match("example", 'examples') nil
现在举一个+
的例子。注意它如何与一个类一起使用,因此它可以匹配一系列不同的字符
> = string.match("this is some text with a number 12345 in it", '%d+') 12345
与+
不同,*
可以不匹配任何内容
> = string.match("one |two| three", '|.*|') |two| > = string.match("one || three", '|.*|') || > = string.match("one || three", '|.+|') nil
使用+
和*
时的一个常见错误是,没有意识到它们会尽可能多地匹配,这可能不是预期的结果。解决此问题的一种方法是使用-
> = string.match("one |two| three |four| five", '|.*|') |two| three |four| > = string.match("one |two| three |four| five", '|.-|') |two| > = string.match("one |two| three |four| five", '|[^|]*|') -- another solution can be to not let the contents match the delimiter |two|
使用-
时,您需要记住从两侧“锚定”它,否则它将不匹配任何内容(因为它尝试尽可能少地匹配)
> = string.match("abc", 'a.*') abc > = string.match("abc", 'a.-') -- the .- part matches nothing a > = string.match("abc", 'a.-$') -- the $ matches the end of the string abc > = string.match("abc", '^.-b') -- the ^ matches the start of the string ab
^
和$
,它们分别匹配字符串的开头和结尾。它们不仅仅用于-
,您只需在模式前加上^
使其在开头匹配,在模式后加上$
使其在结尾匹配,并将它们都包含在内(如上面的示例)使其匹配整个字符串。
最后,您可能在想如何匹配所有这些特殊字符的字面意思。解决方案是在它们前面加上一个%字符
> = string.match("%*^", '%%%*%^') %*^
如果您想从一段文本中获取某些部分,该怎么办?这可以通过将模式的一部分用( )
括起来来实现,每个捕获的内容将从string.match
返回。
> = string.match("foo: 123 bar: 456", '(%a+):%s*(%d+)%s+(%a+):%s*(%d+)') -- %a: letter %s: whitespace foo 123 bar 456
每个捕获都作为单独的结果返回,因此这对于拆分值很有用
date = "04/19/64" m, d, y = string.match(date, "(%d+)/(%d+)/(%d+)") print("19" .. y) --> 1964
有关捕获的更多信息,请参阅手册[2]
特别是如果您习惯于使用其他具有正则表达式的语言,您可能希望能够执行以下操作
'(foo)+' -- match the string "foo" repeated one or more times '(foo|bar)' -- match either the string "foo" or the string "bar"
不幸的是,Lua 模式不支持此功能,只能重复或选择单个字符,而不是子模式或字符串。解决方法是使用多个模式并编写一些自定义逻辑,使用像 lrexlib 或 Lua PCRE 这样的正则表达式库,或者使用 LPeg [3]。LPeg 是一个基于解析表达式语法 [4] 的强大的 Lua 文本解析库。它提供函数在 Lua 代码中创建和组合模式,以及类似于 Lua 模式或正则表达式的语言,以便方便地创建小型解析器。
再次,现在您已经了解了模式的工作原理,请参阅模式手册[1] 以了解所有可能性。