模式教程

lua-users home
wiki

Lua 模式可以匹配字符序列,其中每个字符可以是可选的,也可以重复多次。如果您习惯于使用其他语言的正则表达式来匹配文本,请记住 Lua 的模式匹配与之不同:它更有限,并且语法不同。

阅读完本教程后,强烈建议您阅读模式手册[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
将 % 后的字母大写会反转类,因此 %D 将匹配所有非数字字符。有关所有预定义类的列表,请参阅模式手册(链接在教程顶部)。

您还可以通过将一组字符括在方括号中来创建自己的类。这将匹配这些字符中的一个。如果方括号内的第一个字符是^,那么它将匹配不在该组中的字符。

> = 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]

Lua 模式的限制

特别是如果您习惯于使用其他具有正则表达式的语言,您可能希望能够执行以下操作

'(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] 以了解所有可能性。


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2019 年 4 月 12 日 上午 6:03 GMT (差异)