$ lua -llpeg
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> match = lpeg.match -- match a pattern against a string
> P = lpeg.P -- match a string literally
> S = lpeg.S -- match anything in a set
> R = lpeg.R -- match anything in a range
如果你不想自己创建缩写,你可以这样写:
> setmetatable(_ENV or _G, { __index = lpeg or require"lpeg" })
> digit = R'09' -- anything from '0' to '9'
> digits = digit^1 -- a sequence of at least one digit
> cdigits= C(digits) -- capture digits
> = cdigits:match '123'
123
所以要获得字符串,我们需要用 C 包裹模式。
这个模式没有覆盖到广义上的整型。因为整型可能包括 ‘+’ 或者 ‘-’ 出现在前面 :
> int = S'+-'^-1 * digits
> = match(C(int),'+23')
+23
> sp = P' '^0 -- zero or more spaces (like '%s*')
> function space(pat) return sp * pat * sp end -- surrond a pattern with optional space
> floatc = space(float/tonumber)
> listc = floatc * (',' * floatc)^0
> = match(Ct(listc),' 1,2, 3')
{1,2,3}
function extract_quote(openp,endp)
openp = P(openp)
endp = endp and P(endp) or openp
local upto_endp = (1 - endp)^1
return openp * C(upto_endp) * endp
end
function empty(p)
return C(p)/''
end
quoted_line = empty ('> ') * rest_of_line_nl
...
现在一切都可以正常工作了 !
这是最终用来转换 Markdown 文档到 Lua 维基格式的代码 :
locallpeg=require'lpeg'localP,S,C,Cs,Cg=lpeg.P,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cglocaltest=[[
## A title
here _we go_ and `a:bonzo()`:
one line
two line
three line
and `more_or_less_something`
[A reference](http://bonzo.dog)
> quoted
> lines
]]functionsubst(openp,repl,endp)openp=P(openp)-- make sure it's a patternendp=endpandP(endp)oropenp-- pattern is 'bracket followed by any number of non-bracket followed by bracket'localcontents=C((1-endp)^1)localpatt=openp*contents*endpifreplthenpatt=patt/replendreturnpattendfunctionempty(p)returnC(p)/''endlf=P'\n'rest_of_line=C((1-lf)^1)rest_of_line_nl=C((1-lf)^0*lf)-- indented code blockindent=P'\t'+P' 'indented=empty(indent)*rest_of_line_nl-- which we'll assume are Lua codeblock=Cs(indented^1)/' [[[!Lua\n%1]]]\n'-- use > to get simple quoted blockquoted_line=empty('> ')*rest_of_line_nlquote=Cs(quoted_line^1)/"[[[\n%1]]]\n"code=subst('`','{{%1}}')italic=subst('_',"''%1''")bold=subst('**',"'''%1'''")rest_of_line=C((1-lf)^1)title1=P'##'*rest_of_line/'=== %1 ==='title2=P'###'*rest_of_line/'== %1 =='url=(subst('[',nil,']')*subst('(',nil,')'))/'[%2 %1]'item=block+title1+title2+code+italic+bold+quote+url+1text=Cs(item^1)ifarg[1]thenlocalf=io.open(arg[1])test=f:read'*a'f:close()endprint(text:match(test))
function calc(a, op, b)
a, b = tonumber(a), tonumber(b)
if op == "+" then
return a + b
else
return a - b
end
end
digit = R"09"
calculate = Cf(
C(digit) * Cg( C(S"+-") * C(digit) )^0
, calc
)
calculate:match"1+2-3+4"
--> 4
捕获树看起来是这样的 [*]:
{"Cf", func = calc, children = {
{"C", val = "1"},
{"Cg", children = {
{"C", val = "+"},
{"C", val = "2"}
} },
{"Cg", children = {
{"C", val = "-"},
{"C", val = "3"}
} },
{"Cg", children = {
{"C", val = "+"},
{"C", val = "4"}
} }
} }
Cg(-- [ ** ] ... This one would have been seen,
-- if the search hadn't stopped at *the one*.
"Too late, mate."
, "~@~"
)
* Cg( -- [ 3 ] The search ends here. <--------------[[ Stop ]]
"This is *the one*!"
, "~@~"
)
* Cg(-- [ ** ] ... The great grand parent.
-- Cg with the right tag, but direct ancestor,
-- thus not checked.
Cg( -- [ 2 ] ... Cg, but not the right tag. Skipped.
Cg( -- [ ** ] good tag but masked by the parent (whatever its type)
"Masked"
, "~@~"
)
, "BADTAG"
)
* C( -- [ ** ] ... grand parent. Not even checked.
(
Cg( -- [ ** ] ... This subpattern will fail after Cg() succeeds.
-- The group is thus removed from the capture tree, and will
-- not be found dureing the lookup.
"FAIL"
, "~@~"
)
* false
)
+ Cmt( -- [ ** ] ... Direct parent. Not assessed.
C(1) -- [ 1 ] ... Not a Cg. Skip.
* Cb"~@~" -- [ #### ] <----------------- [[ START HERE ]] --
, function(subject, index, cap1, cap2)
return assert(cap2 == "This is *the one*!")
end
)
)
, "~@~" -- [ ** ] This label goes with the great grand parent.
)