字符串标准库提供了基于模式的4个函数。
string.find 指定目标字符串中搜索指定的模式,找到模式后返回模式开始位置索引和结束位置的索引,没有匹配则返回nil;后两个参数可选,第三个为开始索引的位置,第四个为是否进行简单搜索。
string.match 返回目标字符串中与模式相匹配的子串。
string.gsub 将目标字符串中的所有出现的模式替换成字符串,可以通过第四个参数限制替换次数;返回替换完的字符串和发生替换的次数。
string.gmatch 遍历一个字符中所有出现的指定模式。
模式用到的魔法字符 ( ) . % + - * ? [ ] ^ $
format中的转义字符有效的同时,上面魔法字符通过前加 % 转义,如 %. 表示 .
预置字符分类 (大写形式表示类的补集)
. | 任意字符 |
%a | 字母 |
%c | 控制字符 |
%d | 数字 |
%g | 除空格外的可打印字符 |
%l | 小写字母 |
%p | 标点符号 |
%s | 空白字符 |
%u | 大写字母 |
%w | 字母与数字 |
%x | 十六进制数字 |
使用字符集可创建自定义的字符分类,利用 [ ] 括住所需要的字符即可;通过a-z可以表示连续的许多字符;^ 可以表示当前字符集的补集。
在模式中可以对单个字符或字符分类进行匹配修饰。(模式修饰符)
+ | 重复一次或多次 |
* | 重复零次或多次 |
- | 重复零次或多次(最小匹配) |
? | 出现零次或一次 |
模式以 ^ 开头表示必须从目标字符串开头匹配,以 $ 结尾表示匹配必须到目标字符串的结尾。
模式 "%bxy" 表示匹配成对的字符串,以x起始,到y结束。
模式 "%f[char-set]" 表示只有在后一个字符位于 char-set 内而前一个字符不在时匹配一个空字符串。
模式具有捕获机制,允许根据一个模式从目标字符串中抽出与该模式相匹配的内容。
string.match 会将所有捕获的值作为单独结果返回。
模式 %n 表示匹配第 n 个捕获的副本;%0 表示整个匹配
string.gsub 第三个参数可以是表、函数;当参数是表时,将表第一个捕获的内容作为表的键,表中对应键值作为替换字符串,如果表不存在这个键或键值为 nil 则不改变此匹配;当参数是函数时,参数是当前匹配捕获到的内容,返回值作为替换的字符串,当函数返回值是 nil 时不改变这个匹配。
感觉Lua的模式并不复杂,可以完成许多字符串处理和提取信息;但复杂的模式并不易于阅读,也容易出错,模式修饰符匹配的具体个数还需要实际测试,尤其是一个模式中使用了许多个模式修饰符的时候,很容易拿不准出错。。
练习10.1
--exercise10.1
function spilt(str,mode)
local tab,cnt={},1
for i in string.gmatch(str,string.format(".-%%f[%s]",mode,mode)) do
tab[cnt]=i
cnt=cnt+1
end
for i in string.gmatch(str,string.format("[^%s]+$",mode)) do
tab[cnt]=i
cnt=cnt+1
end
return tab
end
print(table.unpack(spilt("what asd . + whole new world as ","+")))
练习10.2
否,两个互补接触的子集的补集之和为1,'[%D%U]' 表示全部字符。
练习10.3
--exercise10.3
function transliterate(str,tab)
for i in pairs(tab) do
local sp=string.gsub(i,"(%W)","%%%1")
if tab[i]==false then
str=string.gsub(str,sp,"")
else
--tab[i]=string.gsub(tab[i],"(%W)","%%%1")
str=string.gsub(str,sp,tab[i])
end
end
return str
end
b={a=1,b="123",s=false,["["]="]"}
print(transliterate("adsab[[[]abg",b))
模式中的魔法字符需要先加%处理。
练习10.4
--exercise10.4
function trim(s)
s=string.match(s,"%S.*%S")
return s
end
strs=string.rep(" ",102400)
time=os.clock()
trim(" 1"..strs.."1 ")
print(os.clock()-time)
当中间字符存在大量空白字符时,原trim会耗费O(n^2)时间复杂度,如首尾为 1 ,中间102400个空格,i7-4710笔记本跑284.726s。
采用match直接找到非空白字符开头和结尾的最长子串即可。
练习10.5
--exercise10.5
function escape(str)
local cnt=1
str=string.gsub(str,"(.)",function(f)
if cnt<10 then
cnt=cnt+1
return string.format("\\x%02X",string.byte(f))
else
cnt=1
return string.format("\\x%02X\\z\n",string.byte(f))
end
end)
return str
end
print(escape("\0\1hello\200abcdefghijklm\n\a\tnopqrstuvwxyz"))
逐字符转换,每转换10个字符输出 \z 换行一次。
练习10.6
--exercise10.6
function transliterate(str,tab)
str=string.gsub(str,"(.)",function(f)
return "\\"..utf8.codepoint(f)
end)
--print("1>>",str)
for i in pairs(tab) do
--local sp=string.gsub(i,"(%W)","%%%1")
local sp=string.gsub(i,"(.)",function(f)
return "\\"..utf8.codepoint(f)
end)
--print("2>>",sp)
if tab[i]==false then
str=string.gsub(str,sp,"")
else
tab[i]=string.gsub(tab[i],"(.)",function(f)
return "\\"..utf8.codepoint(f)
end)
str=string.gsub(str,sp,tab[i])
end
end
--print("3>>",str)
str=string.gsub(str,"\\(%d+)",function(f)
return utf8.char(f)
end)
--print("4>>",str)
return str
end
b={a=1,b="123",s=false,['+']='qq'}
print(transliterate("bsss+s+a",b))
全部转换成utf8的数字码,替换处理后转为utf8字符。
练习10.7
--exercise10.7
function utf8reverse(str)
local utftab,i={},1
str=string.gsub(str,"(.)",function(f)
utftab[i]=utf8.codepoint(f)
i=i+1
return "\\"..utf8.codepoint(f)
end)
str=string.gsub(str,"\\(%d+)",function(f)
i=i-1
return utf8.char(utftab[i])
end)
return str
end
--print(utf8reverse("bsss+s+a"))
逐字符转换成utf8数字码的同时用序列存储起来,遍历数字码时,从尾到头输出utf8字符。