匹配夏日模式.png
前言#
今天是我每天一篇技术总结计划的第60天,也就是说我坚持每天一篇技术总结已经整整两个月了,我先给自己点个赞。今天也正好是lua函数中string家族里讲解完结的一章,在这一段时间中我们经常会在章节中听到模式匹配这个词,这也是string库函数的强大之处。
Lua并不使用POSIX规范的正则表达式来进行模式匹配。主要的原因出于程序大小方面的考虑:实现一个典型的符合POSIX标准的regexp大概需要4000行代码,这比整个Lua标准库加在一起都大。权衡之下,Lua中的模式匹配的实现只用了500行代码,当然这意味着不可能实现POSIX所规范的所有功能。但是Lua中的模式匹配功能也是很强大的,并且包含了一些使用标准POSIX模式匹配不容易实现的功能。
前面几章一直跟大家说会总结一下模式匹配这一块的内容,今天是周末我就利用多一点时间,根据lua官方文档中关于模式的介绍为主线,我们一起来总结一下lua中关于模式匹配的内容,其中大部分内容官方文档已经介绍过了,我就是翻译一下,可能有理解不正确的地方,欢迎大家批评指正。
内容#
string patterns##
1.Character Class
一个字符类可以被用于表示一组字符,以下组合被允许来来描述一个字符类:
-
x:表示字符x本身(这里的x表示不是魔法字符^$()%.[]*+-?中的一个)。 -
.:表示所有字符(一个点/英文中句号)。 -
%a:表示所有字母。 -
%c:表示所有控制字符。 -
%d:表示所有十进制数字。 -
%l:表示所有小写字母。 -
%p:表示所有标点符号。 -
%s:表示所有空白字符。 -
%u:表示所有大写字母。 -
%w:表示所有字母和数字。 -
%x:表示所有十六进制数。 -
%z:表示0值字符。 -
%x:表示字符x(此处的字符x不是字母或数字)。这是讲魔术字符转义的标准方式,当被用于在模式中表示自身时,任何标点符号(甚至非魔术的)都能加一个前缀%。 - [set]:表示set中的所有字符的联合构成的分类。通过用
-分隔截止字符可以指定某个范围的字符。上面描述的所有种类的%x都可用作set的组成部分。set中的所有其他字符表示它们自身。例如[%w_](或[_%w])表示所有字母数字字符和下划线,[0-7]表示八进制数字,[0-7%l%-]表示八进制数字和小写字母以及-字符。 - [^set]:表示set的补集,其中的set在上面解释了。
- 字符范围和字符类之间的相互作用是未定义的。因此类似[%a-z]或[a-%%]的模式没有意义。
- 对于所有单字母表示的字符类(
%a、%c等等),相应的大写字母表示该字符类的补集。例如,%S表示所有非空白符。 - 字母、空白和其他字符组合的定义依赖于当前locale。特别地,字符类[a-z]可能不等于%l。
2.Pattern Item
一个模式选项可以是:
- 一个单个字符类,它匹配该类中的任意单个字符。
- 一个后跟
*的单个字符类,它匹配该类中的0或多个字符。这些重复项将总是匹配最长的可能序列。 - 一个后跟
+的单个字符类,它匹配该类中的1或多个字符。这些重复项将总是匹配最长的可能序列。 - 一个后跟
-的单个字符类,它也匹配该类中的0或多个字符。与*不同,这些重复项将总是匹配最短的可能序列。 - 一个后跟
?的单个字符类,它匹配出现0或1次该类中的字符。 -
%n中的n在1和9之间,这种项匹配一个等价于捕获的字符串的第n个子串(见下面) -
%bxy中x和y是两个不同的字符;这种项匹配始于x终于y的字符串,并且x和y是对称的。这表示,如果一个人从左到右读字符串,对x计数为+1,对y计数为-1,结尾的y是第一个遇到计数为0的y。例如,项%b()匹配带有平衡的圆括号的表达式。
3.Pattern
模式是一系列的模式项。在模式开头的^将匹配固定在源串的开头。在模式结尾的$将匹配固定在源串的结尾。在其他位置上,^和$没有特殊含义,表示它们自身。
4.Captures
模式可以含有括在圆括号内的子模式,它们描述捕获。当成功进行一个匹配,源串中匹配捕获的子串被存储(捕获)以便将来使用。捕获根据它们的左圆括号进行编号。例如,在模式"(a*(.)%w(%s*))"中,字符串的匹配"a*(.)%w(%s*)"的部分作为第一个捕获被存储(因此被编号为1),匹配"."的字符被捕获并编号为2,匹配"%s*"的部分被编号为3。
作为一种特殊情况,空捕获()捕获当前字符串位置(一个数字)。例如,如果我们把模式()aa()用于字符串"flaaap",将有两个捕获:3和5。
模式不能含有内嵌的0(即'\0')。使用%z代替。
usage##
- 首先我们新建一个文件将文件命名为patterntest.lua然后编写代码如下:
-- 这是一个原串
local sourcestr = "ehrt999wj=--=-*-/4mdqwl\0ds123tfef"
print("\nsourcestr = "..string.format("%q",sourcestr));
-- '%z'的使用
local match_ret = string.match(sourcestr, "%z")
print("\n%z match_ret is ", string.format("%q",match_ret))
-- '*'的使用
match_ret = string.match(sourcestr, "%a*")
print("\n%a* match_ret is ", string.format("%q",match_ret))
-- '-'的使用(其实我有点迷糊)
match_ret = string.match(sourcestr, "%a%d-")
print("\n%a- match_ret is ", string.format("%q",match_ret))
-- '%bxy'的使用
match_ret = string.match(sourcestr, "%bhs")
print("\n%bhs match_ret is ", string.format("%q",match_ret))
-- '()xxx()'的使用
local match_ret1, match_ret2 = string.match(sourcestr, "()t9()")
print("\n()t9() match_ret is ", string.format("%q",match_ret1),
string.format("%q",match_ret2))
- 运行结果
string_pattern.png
总结#
- 为了测试其中一些字符类的效果,我们使用了函数
string.match()这个相对简单的函数,可以说明问题就行了。 - 在代码中我们举了几个不太好理解的例子,比如
%z、%bxy、%a*等,大家可以看一下输出结果感受一下。 - 在例子中特别是最后一个不太好理解,我的理解是第一个括号输出的索引是捕获字符串的第一个位置,后一个括号输出的是捕获字符串结束的后一个位置。













网友评论