文章目录
本来想继续放在同一篇测试博客的 LearnLua - 学习笔记,但是发现单一一篇博客太多 Markdown 内容会卡到爆,所以还是分开来写了
string match pattern - 字符匹配
其实这算是 lua 内置的正则表达式吧,只不过它的转义符为 %
而不是我们其他 C 类语言的 \
可以查看官方文档的简述(正的很简述,如果你以前没使用过正则,就不建议查看官方的简述文档帮助不大,硬是从 lua 的正则来入门的话,我建议你买 lua 的书籍)
官方资料:官方简述文档-string
- string.gmatch(s, pattern, [, init])
s
是需要匹配的正文pattern
是正则表达式init
是可选项,就是在s
的第几个字符开始匹配,默认为 1@return
返回的是 group 分组 的匹配结果,如果正则表达是没有用分组匹配,那么返回的就是匹配的字符内容
- string.gsub (s, pattern, repl [, n])
s
是需要匹配的正文pattern
是正则表达式repl
设置repl
就可以将匹配到的字符内容替换为repl
的内容n
另外正则表达式可以在 vsc 或是 sublime 中很方便的验证匹配性,一般会我选择在 sublime 中输入需要匹配的文本内容,然后 Ctrl + F 或是 Ctrl + H(如果需要替换的话)然后勾上正则开关,就可以输入正则表达式来测试匹配了
string.gmatch - 分组匹配
它返回的是匹配到的字符迭代器函数
官方的例子:
Returns an iterator function that, each time it is called, returns the next captures from pattern (see §6.4.1) over the string s. If pattern specifies no captures, then the whole match is produced in each call. A third, optional numeric argument init specifies where to start the search; its default value is 1 and can be negative.
As an example, the following loop will iterate over all the words from string s, printing one per line:
s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
print(w)
end
The next example collects all pairs key=value from the given string into a table:
t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "(%w+)=(%w+)") do
t[k] = v
end
下面是我自己测试的例子
local test_str = "a + b = c;\n1 + 2 =3;100-1=99;var1 + var2= var3 ;"
for _1, _2, _3, _4, _5 in string.gmatch(test_str, "(%w+)%s*([%+|%-|%*|%%|%^])%s*(%w+)%s*=%s*(%w+)%s*;%s*([\n]*)") do
print(_1.._2.._3.."=".._4..";")
end
--[=[
输出:
a+b=c;
1+2=3;
100-1=99;
var1+var2=var3;
]=]
在编写 string.gmatch
那串匹配正则表达式之前,我们可以在 sublime 下演示一下匹配的方式,然后还可以查看替换结果
string.gsub(s, pattern, repl [, n]) - 替换字符功能
首先吐槽一下,函数名字不太友好
它作用是返回 s
使用 pattern
匹配到的内容(这个返回值可以有多个,也可以根据使用的分组数量来返回匹配的字符串数量),再使用 repl
来替换匹配的内容,n
是要执行替换的分组数量,不填就是使用所有分组
下面给是官方的示例:
x = string.gsub("hello world", "(%w+)", "%1 %1")
--> x="hello hello world world"
x = string.gsub("hello world", "%w+", "%0 %0", 1)
--> x="hello hello world"
x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
--> x="world hello Lua from"
x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
--> x="home = /home/roberto, user = roberto"
x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
return load(s)()
end)
--> x="4+5 = 9"
local t = {name="lua", version="5.4"}
x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
--> x="lua-5.4.tar.gz"
下面是我自己的测试用例:
function test_expr(n)
local exp1 = "My Name is : xxx,My Name is : xxx2"
local repl_str, repl_count
-- using function
print("=== using function ===")
repl_str, repl_count = string.gsub(exp1, "My Name is%s*:%s*(%w+)", function(name) print("Capture your name : " .. name) return "\""..name.."\"" end, n)
print("repl_str:"..repl_str)
print("repl_count:"..repl_count)
-- using table
print("=== using table ===")
local repl_tbl_data = {xxx="tom", xxx2="jerry"}
repl_str, repl_count = string.gsub(exp1, "My Name is%s*:%s*(%w+)", repl_tbl_data, n)
print("repl_str:"..repl_str)
print("repl_count:"..repl_count)
-- using string1
print("=== using string1 ===")
repl_str, repl_count = string.gsub(exp1, "My Name is%s*:%s*(%w+)", "uniform_name", n)
print("repl_str:"..repl_str)
print("repl_count:"..repl_count)
-- using string2
print("=== using string2 ===")
repl_str, repl_count = string.gsub(exp1, "My Name is%s*:%s*(%w+)", "%0", n) -- %0 is original string content
print("repl_str:"..repl_str)
print("repl_count:"..repl_count)
-- using string3
print("=== using string3 ===")
repl_str, repl_count = string.gsub(exp1, "My Name is%s*:%s*(%w+)", "%1", n) -- %1 is the number of the match group
print("repl_str:"..repl_str)
print("repl_count:"..repl_count)
end
print("============ test_expr() ======")
test_expr()
print("============ test_expr(0) ======")
test_expr(0)
print("============ test_expr(1) ======")
test_expr(1)
print("============ test_expr(2) ======")
test_expr(2)
--[=[
============ test_expr() ======
=== using function ===
Capture your name : xxx
Capture your name : xxx2
repl_str:"xxx","xxx2"
repl_count:2
=== using table ===
repl_str:tom,jerry
repl_count:2
=== using string1 ===
repl_str:uniform_name,uniform_name
repl_count:2
=== using string2 ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:2
=== using string3 ===
repl_str:xxx,xxx2
repl_count:2
============ test_expr(0) ======
=== using function ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:0
=== using table ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:0
=== using string1 ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:0
=== using string2 ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:0
=== using string3 ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:0
============ test_expr(1) ======
=== using function ===
Capture your name : xxx
repl_str:"xxx",My Name is : xxx2
repl_count:1
=== using table ===
repl_str:tom,My Name is : xxx2
repl_count:1
=== using string1 ===
repl_str:uniform_name,My Name is : xxx2
repl_count:1
=== using string2 ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:1
=== using string3 ===
repl_str:xxx,My Name is : xxx2
repl_count:1
============ test_expr(2) ======
=== using function ===
Capture your name : xxx
Capture your name : xxx2
repl_str:"xxx","xxx2"
repl_count:2
=== using table ===
repl_str:tom,jerry
repl_count:2
=== using string1 ===
repl_str:uniform_name,uniform_name
repl_count:2
=== using string2 ===
repl_str:My Name is : xxx,My Name is : xxx2
repl_count:2
=== using string3 ===
repl_str:xxx,xxx2
repl_count:2
]=]
从 test_expr(1) 与 test_expr(2) 可以看出来 n
参数的作用就是使用分组数量的参数
Custom split(s, ss) - 自定义分割函数
通过前面的测试,我们可以使用 string.gmatch
来匹配分割字符的功能
local test_str = "1;2;3"
for v in string.gmatch(test_str, "([^;]*)") do
if v ~= "" then -- pass empty
print("match str : " .. v)
end
end
--[=[
输出:
match str : 1
match str : 2
match str : 3
]=]
那么我们可以自己封装一个函数 Split(s, ss)
s
是我们需要分割的原文ss
是我们需要匹配的分割符,可以是正则(这就很方便了,不过一般很少使用正则来所分割符匹配,一般就写死一个字符或是字符串就好)
function split(s, ss)
local ret = {}
for v in string.gmatch(s, "[^"..ss.."]*") do
-- print("v:" .. v)
if v ~= "" then -- pass empty
-- print("match str : " .. v)
table.insert(ret, v)
end
end
return ret
end
local test_str = "Tom;Jerry;Tony;Jacky"
local split_ret = split(test_str, ";") -- 不需要分组() 了,因为用不上
for i=1, #split_ret do
print("split_ret[" .. i .. "]=" .. split_ret[i])
end
--[=[
输出:
split_ret[1]=Tom
split_ret[2]=Jerry
split_ret[3]=Tony
split_ret[4]=Jacky
]=]