Lua模式匹配

本文详细介绍了Lua语言的模式匹配,包括相关函数如string.find、string.match和string.gmatch的用法,以及模式、捕获和替换等概念。讨论了模式匹配的特性,如字符分类、魔法字符、重复和可选部分的修饰符,并提供了实用的示例,如URL编码和制表符展开。同时,文中还提到了模式匹配的技巧和注意事项,强调了精确模式和空模式的使用陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章新地址
    与其他几种脚本语言不通,Lua语言既没有使用POSIX正则表达式,也没有使用Perl正则表达式来进行模式匹配。之所以这样做的主要原因在于大小问题:一个典型的POSIX正则表达式实现需要超过4000行代码,这比所有Lua语言标准库总大小的一半还大。相比之下,Lua语言模式匹配的实现代码只有不到600行。尽管Lua语言的欧式匹配做不到完整POSIX实现的所有功能,但是Lua语言的模式匹配仍然非常强大,同时还具有一些与标准POSIX不同但又可与之媲美的功能。

模式匹配的相关函数

    字符串标准库提供了基于模式的4个函数。我们已经初步了解过函数find和gsub,其余两个函数分别是match和gmatch。

函数string.find

    函数string.find用于在指定的目标字符串中搜索指定的模式。最简单的模式就是一个单词,它智慧匹配到这个单词本身。例如,模式’hello’会在目标自服装中所搜子串"hello"。函数string.find找到一个模式后,会返回两个值:匹配到模式开始位置的索引和结束位置的索引。如果没有找到任何匹配,则返回nil:

s = "hello world"
i,j = string.find(s,"hello")
	print(i,j)				-- 1	5
	print(string.sub(s,i,j)) -- hello
	print(string.find(s,"world"))	--	7	11
	i,j = string.find(s,"l")
	print(i,j)			-- 3	3
	print(string.find(s,"lll"))		-- nil

匹配成功后,可以以函数find返回的结果为参数调用函数string.sub来获取目标字符串匹配相应模式的子串。对于简单的模式来说,这一般就是模式本身。
    函数string.find具有两个可选参数。第3个参数是一个索引,用于说明从目标字符串的哪个位置开始搜索。第4个参数是一个布尔值,用于说明是否进行简单搜索。所谓简单所有就是忽略模式而在目标字符串中进行单纯的“查找子字符串”的动作:

> string.find("a[word]","[")
stdin:1:malformed pattern (missing ']')
> string.find("a [word]","[",1,true) 		-- 3	3

由于’[‘在模式中具有特殊含义,因此第1个函数调用会报错。在第2个函数调用中,函数只是把’['当作简单字符串。请注意,如果没有第3个参数,是不能传入第4个可选参数的。

函数string.match

    由于函数string.match也用于在一个字符串搜索模式,因此它与函数string.find非常相似。不过,函数string.match返回的是目标字符串中与模式相匹配的那部分子串,而非该模式所在的位置:

print(string.match("hello world","hello"))			-- hello

对于诸如’hello’这样固定的模式,使用这个函数并没有什么意义。然而,当模式是变量时,这个函数的强大之处就显现出来了。例如:

date = "Today is 15/4/2020"
d = string.match(date,"%d + /%d + /%d +")
print(d)		-- 15/4/2020

函数string.gmatch

     函数string.gmatch返回一个函数,通过返回的函数可以遍历一个字符串中所有出现的指定模式。例如,以下示例可以找出字符串s中出现的所有单词:

s = "some string"
words = {
   }
for w in string.gmatch(s,"%a+") do 
	words[#words + 1] = w
end

模式

     大多数模式匹配库都是用反斜杠作为转义符。然后,这种方式可能会导致一些不良的后果。对于Lua语言的解析器而言,模式仅仅是普通的字符串。模式与其他的字符串一样遵循相同的规则,并不会被特殊对待;只有模式匹配相关的函数才会把它们当做模式进行解析。由于反斜杠是Lua语言中的转义符,所以我们应该避免它传递给任何函数。模式本身就难以阅读,到处把“\”换成“\”就更加火上浇油了。
     我们可以使用双括号把模式括起来构成的长字符串来解决这个问题。然而,长字符串的写法对于通常比较短的模式而言又往往显得冗长。此外,我们还会失去在模式内进行转义的能力。
     Lua语言的解决方案更加简单:Lua语言中的模式使用百分号作为转义符。总体上,所有被转义的字母都具有某些特殊含义,而所有被转移的非字母则代表其本身。
     我们首先来学习字符分类的模式。所谓字符分类,就是模式中能够与一个特定集合中的任意字符相匹配的一项。例如,分类%d匹配的是任意数字。因此,可以使用模式’%d%d/%d%/d%d%d%d’来匹配dd/mm/yyyy格式的日期:

s = "Deadline is 15/04/2020, firm
date = "%d%d/%d%d/%d%d%d%d"
print(string.match(s,date))		-- 15/04/2020

下表列出了所有预置的字符串分类及其对应的含义:


.           任意字符
%a           字母
%c           控制字符
%d           数字
%g           除空格外的可打印字符
%l           小写字母
%p           标点符号
%s           空白字符
%u           大写字母
%w           字母和数字
%x           十六进制数字


     这些类的大写形式表示类的补集。例如,%A代表任意非字母的字符:

print((string.gsub("hello, up-down!","%A","."))) -- hello..up.down.

在输出函数gsub的返回结果时,我们使用了额外的括号来丢弃第二个结果,也就是特换发生的次数。
     当在模式中使用时,还有一些被称为魔法字符的字符具有特殊含义。Lua语言的模式所使用的魔法字符包括:
() . % + - * ? [ ] ^ $
正如我们之前已经看到的,百分号同样可以用于这些魔法字符的转义。因此,%?匹配一个问号,%%匹配一个百分号。我们不仅可以用百分号对魔法字符进行转义,还可以将其用于其他所有字母和数字外的字符。当不确定是否需要转义时,为了保险起见就可以使用转义符。
     可以使用字符集来创建自定义的字符分类,只需要在方括号内将单个字符和字符分类组合起来即可。例如,字符集[%w_]匹配所有以下画线结尾的字母和数字,[01]匹配二进制数字,[%[%]]匹配方括号。如果想要统计一段文本中元音的数量,可以使用如下的代码:

_,nvow 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南锋1

您的打赏是我继续创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值