LUA 正则表达式 - 模式匹配


 

模式匹配相关库函数

 

按匹配查找:string.find (s,pattern [,init [,plain]])

两个返回值,被捕获内容的起始位置和终止位置,如未找到则返回nil。

参数s:指定字符串,参数pattern:匹配,可选参数init:初始查找位置(如果是负数将从字符串尾开始定位),可选参数plain:无参数时按匹配查找,当参数为true时使用单纯字符串进行匹配。

 

按位置捕获:string.sub (s,i [,j])

返回以i,j定位的子串内容。

参数s:指定字符串,参数i:初始查找位置(如果是负数将从字符串尾开始定位),可选参数j:无参数时等价j为最大值,如果j比整个字符串大则自动修正,如果j比i小则返回空字符串。

 

按匹配捕获:string.match (s,pattern [,init])

返回按匹配捕获的子串,如未捕获则返回nil。如果在参数pattern中使用()进行捕获则返回值变为捕获到内容。

参数s:指定字符串,参数pattern:匹配,可选参数init:初始查找位置(如果是负数将从字符串尾开始定位)

 

按匹配捕获并替换:string.gsub (s,pattern,replace [,n])

两个返回值,成功替换后的新字符串和被替换的次数,如未找到匹配则返回s原始内容。

参数s:指定字符串,参数pattern:匹配,参数replace:替换内容(可以是表或函数),可选参数n:替换次数,无参数则全部替换。

 

迭代器函数:string.gmatch (s,pattern)

每次迭代返回一个匹配的子串内容,该函数用于逐一遍历字符串中所有捕获到的匹配。

参数s:指定字符串,参数pattern:匹配

 

模式匹配预置的字符分类

 .  -- 任意字符
%a  -- 字母
%c  -- 控制符,如\n
%d  -- 数字
%g  -- 除空格外的可打印字符
%l  -- 小写字母
%p  -- 标点符号
%s  -- 空白字符
%u  -- 大写字母
%w  -- 字母和数字
%x  -- 十六进制数字
%n  -- 第n次被()捕获的内容,n是一个数字,如:%1 %2 %3,而%0则意味着整个匹配而不是捕获
%f  -- 前置排除模式
%b  -- 范围匹配,使用两个字符参数确定前后成对的区域,如:%b<> %b{} %b33 %b-+ 遵循最远距离贪婪匹配规则

 

魔法字符(修饰符)

 %  -- 转义符
 +  -- 重复一次或多次
 *  -- 重复零次或多次(最远距离贪婪匹配)
 -  -- 重复零次或多次(最近距离匹配)
 ?  -- 重复零次或一次(表示可有可无)
 ^  -- 锚定开头
 $  -- 锚定结尾
[]  -- 自定义字符分类,分类间的关系是"或"
()  -- 捕获,空的捕获可以返回位置信息,如:字符串"Name",模式"()am()"返回2,4。
   使用修饰符时一定要注意上下文,如:.*很可能匹配超预期
   在结尾使用"-"并没有意义,这样只能匹配到空字符,-后面总是要跟上一些东西来限制扩展范围

 

当模式匹配字母大写时表示其补集,非字母代表其本身,在模式中%需要转义,如%%。而匹配无意义的修饰符时也需要加转义字符%。

前置排除模式:简单来说%f[char-set]是判断[char-set]后面紧跟的字符是否属于[char-set]而[char-set]之前的字符不属于[char-set],例如:"%f[%a]abc123"对于字符串"Hi+abc123"来说,字符a属于[%a]而前面的+不属于[%a]即模式成立。

()捕获与%n配合可以对[]自定义字符分类中不确定的内容在后续进行进一步的确认。

例如:

s = [[then he said: "it's all right"!]]
print (string.match (s, "(["'])(.-)%1")
-->" it's all right 输出了两个参数,分别是"和it's all right。
以"或'开头,零个或多个任意字符序列,遇到第一次捕获到的匹配为结尾,使得不确定的字符分类在最后得到了确定的匹配
类似的例子如:长字符串或长注释[==[ ]==]中不确定的=数量

 

翻译一些例子

"[_%a][_%w]*"  -- [下划线任意字母][零个或多个下划线任意字母或数字]*,匹配LUA中合法的标识符

"[+-]?%d+"     -- [可有可无的正号负号]?任意数字序列+,匹配123,-21,+456

"^%d"          -- 任意数字开头^,匹配整段字符串第一个字符是数字

"^[+-]?%d+$"   -- 开头^[可有可无正号负号]?任意数字序列结尾$,匹配纯整型数值

"%[(=*)%[(.-)%]%1%]"  -- 转义[捕获1(零个或多个等号)转义[捕获2(零个或多个任意字符)转义]捕获1的内容%1转义],匹配LUA长字符串样式[==[]==]

 

替换

string.gsub的第三个参数不仅可以是字符串,还可以是函数或者表。

string.gsub配合%n替换

例如:

print (string.gsub ("Hello Lua", "(.)(.)", "%2%1"))
--> eHll ouLa    4,将相邻的两个任意字符换位,共替换4次

当替换参数是函数时,会在每一次找到匹配时调用这个函数,并以捕获的内容为参数,以这个函数返回值作为替换内容。

当替换参数是表时,会把第一个捕获内容作为键,去查找表中的值作为替换内容,如果不成功,则当次不做任何替换。

例如:

tb={}
tb.Hello="+"
print (string.gsub ("Hello Lua", "%a+", tb))
--> + Lua    2, 以匹配到的字符序列为键去获取表tb中对应该键的值,如果是标准字符串则使用这个字符串替换,如果没找到键或者值不是字符串类型则不做改变。
本示例匹配到了2次但只替换1次。

 

小程序练习

-- 给定一个字符串,找出字符串中所有单词并计算重复的次数,输出前进行排序,优先输出重复最多的单词
do
    local txt = [[hi hi lua aaa b c c c cc]] -- 指定字符串
    local tbl = {}

    for key in string.gmatch(txt, "%a+") do  -- 每次迭代逐个捕获表中单词,存入表tbl
        tbl[key] = (tbl[key] or 0) + 1       -- 作为键存表,其值做一次计数自增
    end
    
    local words = {}
    for k, v in pairs(tbl) do                -- 把无序表tbl的键作为值按顺序导入表words
        words[#words + 1] = k
    end

    table.sort (words, function(v1, v2) return tbl[v1] > tbl[v2] or tbl[v1] == tbl[v2] and v1 < v2 end)
    -- 排序表words,比较tbl中相关键的值(重复的次数),优先按次数最多排序,如果次数相等则按首字母顺序排
    for _,v in ipairs(words) do              -- 遍历数组输出
        print ("单词 "..v.." 被找到 "..tbl[v].."")
    end
end

--[[ 输出结果
单词 c 被找到 3 次
单词 hi 被找到 2 次
单词 aaa 被找到 1 次
单词 b 被找到 1 次
单词 cc 被找到 1 次
单词 lua 被找到 1 次
--]]

 

学习辅助工具

Lua正则在线测试工具 (luatos.com)

LuatOS 在线模拟 - lua在线测试

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM