欢迎光临散文网 会员登陆 & 注册

LUA 正则表达式 - 模式匹配

2023-07-18 23:19 作者:绥宁大魔王  | 我要投稿

按匹配查找: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].." 次")    endend

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

LUA 正则表达式 - 模式匹配的评论 (共 条)

分享到微博请遵守国家法律