LPEG库简介

0 篇文章 0 订阅

LPEG是一个供lua使用的基于 Parsing Expression Grammars 的模式匹配库,这篇文章只是讲其如何使用,并不涉及底层如何实现。

LPEG 的函数主要分为三类,第一类是创建Pattern的构造函数,第二类是 Capture 函数, 第三类则是 match 等函数。 Capture 就是指一个Pattern,当前匹配时会产生某些捕获的值

Match 等函数

lpeg.match (pattern, subject [, init])

以上为 match 函数, 第一个参数为用来匹配的 pattern,第二个参数则为用来匹配的字符串, 可选参数 init指明 subject 开始匹配的位置, 负数指从subject 结尾处开始数。另外, match 函数中还可以传入一些额外参数, 供 capture 使用,这个后面涉及到的时候再讲。

match 函数只匹配给定subject(计算过 init参数之后的subject)字符串的前缀, 而不是匹配其任意位置。不过,我们可以通过一些方式改写 pattern, 使其匹配任意位置的subject。

match的返回值有两种情况,一种是返回 pattern 匹配时捕获的值, 如果没有捕获的值则返回pattern匹配后subject的第一个字符的index, 比如 pattern 为匹配任意一个字符, 则返回值为2。 这个在后面的例子里会再具体讲。 如果匹配 pattern失败,则返回 nil。

lpeg.type (value)

value 是 Pattern 时, 返回 “pattern”; 否则, 返回 nil。

lpeg.version()

返回 Lpeg 的版本

lpeg.setmaxstack (max)

这个函数是设置Lpeg解析过程中允许使用的栈的大小,默认400, 这里就不展开讲了。

创建 Pattern 的构造函数

lpeg.P (value)

将 value 转变为 patten。value 可以是以下值

  • pattern, 返回 pattern
  • string, 返回匹配该string固定值得pattern
  • 非负数n, 返回一个匹配 n 个字符的 pattern
  • 负数 -n, lpeg.P(-n) = -lpeg.P(n), 即匹配任意 不匹配 lpeg.P(n)的subject, 所以匹配少于n个字符的 subject, 注意的是,它不会消耗任何字符,比如 n = 3, subject = “ab”, match成功后返回的 index 是1, 就像没有匹配过一样。
  • boolean , 返回一个 Pattern, 匹配总是 失败 或者 成功, 也不消耗任何字符
  • function, 相当于lpeg.Cmt(”, function), 这个后面讲Capture时会讲到。
    期待使用pattern时传入以上的值,也会通过lpeg.P 函数转换为pattern。

lpeg.B(patt)

在subject 的当前 index 之前匹配patt, 不消耗任何字符, 并且 patt只可以是那种不是匹配无限长度字符串的pattern。

> b = lpeg.B("str")
> print (lpeg.match(b, "istrim", 5))
5
> print (lpeg.match(b, "istrim", 6))
nil

以上实例为在位置5之前匹配str, 匹配成功返回当前 index 5 , 若改为从位置6开始匹配,则匹配失败,返回nil。

lpeg.R ({range})

返回一个pattern, 可以匹配range范围内的任一字符。
lpeg.R(“09”), 匹配 0-9.
lpeg.R(“az”), 匹配 a-z,
lpeg.R(“az”, “AZ”) 匹配 a-z, A-Z

lpeg.S (string)

匹配出现在string中的任意字符

lpeg.V (v)

根据index v 创造一个作为非终结符的变量.
在讲这个之前,我们要讲一下 Lpeg 中的Grammar, 通过各种函数来组合pattern,无法表达包含递归的Pattern,所以需要使用Grammar来构造。
Grammar 是使用 table 来表示的, 每一个元素都代表一个rule, index 为 1的代表 initial rule,如果 index 为1的是一个字符串,则代表initial rule的index。 通过 lpeg.P(table) 可以将table 转换为pattern,转换之后得到的pattern会匹配table中的initial rule。

equalcount = lpeg.P{
  "S";   -- initial rule name
  S = "a" * lpeg.V"B" + "b" * lpeg.V"A" + "",
  A = "a" * lpeg.V"S" + "b" * lpeg.V"A" * lpeg.V"A",
  B = "b" * lpeg.V"S" + "a" * lpeg.V"B" * lpeg.V"B",
} * -1

相当于

 S <- 'a' B / 'b' A / ''
 A <- 'a' S / 'b' A A
 B <- 'b' S / 'a' B B
 48 function anywhere (p) --这个函数是指将p转换为可以匹配subject任意位置子字符串的p
 49   return lpeg.P({ p + (1 * lpeg.V(1)) })
 50   end
 51 
 52 print(anywhere(lpeg.alpha^1):match(",,ab,,"))--匹配大于一个的字母,故返回5
 53 print("l48:",anywhere(lpeg.alpha^1):match(",,,,"))--返回nil

lpeg.locale ([table])

在table中添加一些lpeg定义好的pattern, 比如 alnum, alpha, cntrl, digit, graph, lower, print, punct, space, upper, and xdigit.
lpeg.locale(t), 则 t.alpha 返回一个可以匹配字母的pattern

#patt

匹配patt,但不消耗任何字符,这在前面已经说明过。需要注意的是,patt中不会产生capture。

-patt

匹配不匹配patt的subject。不产生字符消耗。不产生任何capture。

patt1 + patt2

匹配 patt1 或者 patt2, 这是有序的,即优先匹配patt1, 这也是 PEG 与 CFG的最大区别。

patt1 - patt2

保证不匹配patt2, 然后匹配patt1

patt1 * patt2

先匹配 patt1, 再匹配 patt2

patt^n

若n为非负数,则匹配 n 或者更多的patt;若n为负数,则最多匹配n个patt。

Captures

一个capture pattern 在匹配成功的时候产生捕获的值。通常情况下,capture只会在整个匹配结束之后才求capture的值,在匹配期间,只会收集足够的信息来产生之后的capture的值。并且,绝大部分的capture值是不会影响到匹配的结果的。但是,lpeg.Cmt(patt,function)是一个例外,它强制在匹配时生成所有它嵌套的capture的值,然后调用相应的函数,该函数会决定匹配是否成功,并且产生相应的值。

lpeg.C(patt)

捕获subject中匹配patt的子字符串。如果patt有其他capture,则会跟在后面返回,即会返回多个变量。

lpeg.Carg(n)

匹配空字符串,返回lpeg.match()函数的第n个额外参数,我们将match的时候也提到过。

lpeg.Cb (name)

匹配空字符串,捕获之前最近的一个group capture 中名叫name的值。

Most recent means the last complete outermost group capture with the given name. A Complete capture means that the entire pattern corresponding to the capture has matched. An Outermost capture means that the capture is not inside another complete capture.

以上是对最近一个group capture的说明,为了避免词不达意,就贴上原文。

lpeg.Cc ([value, …])

匹配空字符串,将所有的value作为捕获的值。

lpeg.Cf (patt, func)

如果patt捕获的值为C1, C2,…, Cn, 该Capture则会返回 (…func(func(C1,C2),C3)…, Cn).

lpeg.Cg (patt [, name])

将patt捕获的值打包成一个capture,仍旧是多个变量的形式。group可以是匿名的或者是有名字的,匿名的是将多个capture打包成一个capture。有名字的则是为了back capture(lpeg.Cb (name)) 和 table captue(lpeg.Ct (patt))使用。
需要注意的是,有名字时其本身就不会返回捕获的值,而是返回匹配后字符的index。

lpeg.Cp ()

匹配空字符串,捕获subject当前位置。

lpeg.Cs (patt)

捕获patt匹配的子字符串。在patt中,会有一些捕获的值,最后,将子字符串在patt中匹配的值的子字符串,替换成其对应的捕获的值, 通常配合patt/string 来达到替换字符串的效果。

local rep = name/"name";--name匹配任意长度的字母
print(rep:match(“hi=ab”)) -- 匹配hi,返回捕获的值 “name”
print(lpeg.Cs((rep+1)^0):match("hi=ab")) --匹配成功,返回子字符串hi=ab,其中hi和ab都匹配rep,将其替换成rep捕获的值name,则返回“name=name”

lpeg.Ct (patt)

创建一个table,将patt所有匿名捕获的值从键值1开始存入table,如果是Cg中捕获的有名字的group,该group中的第一个值会被存入table中,group的名字就是它对应的键值。

patt / string

匹配patt,返回string。
如果string是%n,n为1-9,则返回patt中第n个捕获的值。%0 返回整个匹配的值.
%%代表字符%。

patt / number

返回patt中第n个捕获的值,如果number = 0, 没有捕获的值。

patt / table

将patt第一个捕获的值作为key,没有则将整个匹配的值作为key,table[key]就是最好捕获的值,如果没有,则没有捕获的值。

patt / function

将patt捕获的值全部作为参数传递给function,没有则将整个capture作为参数,function返回的值就是捕获的值,没有返回值,则没有捕获的值。

lpeg.Cmt(patt, function)

将整个subject,当前index,捕获的值作为参数传递给function。
function返回数字的话,匹配成功,并且将该数字作为subject新的index。如果返回true,则匹配成功,不消耗任何字符。如果返回false,nil,不返回任何字符,匹配失败。
该函数返回的额外值,作为该Capture捕获的值。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值