[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Proposal for new LPeg function: lpeg.Ctab()
- From: Patrick Donnelly <batrick@...>
- Date: Wed, 14 Sep 2016 09:59:00 -0400
On Tue, Sep 13, 2016 at 2:59 PM, Sean Conner <sean@conman.org> wrote:
>
> Seeing how there's going to be a bug fix for LPeg Real Soon Now (TM), I
> thought it might be a good time to float a proposal for a new lpeg function.
>
> Some background: I parse a lot of Internet related messages and URLs
> (email and SIP messages, sip:, tel:, http: and https: URLs, etc.) and it's
> amazing how often name/value pairs keep popping up. Usually there are a
> fixed number of defined name/value pairs but the grammars almost always
> allow user defined pairs. Since I use LPeg for all of my parsing needs, I
> like to parse the data into Lua tables and the most problematic part is
> handing open ended name/value pairs.
>
> Let me give a simplified example: A simple file of name/value pairs
> (alpha characters only---I want to keep things really simple) one per line,
> name and value separated by an '=' sign; order does not matter. There are
> two fields defined, "foo" and "bar" (which if not provided, default values
> will be given). Two examples follow:
>
> Example 1:
> foo=de
> bar=true
> alpha=Sean
> bravo=Conner
>
> Example 2:
> yankee=Sean
> zulu=Conner
> foo=se
How about this:
---
local lpeg = require"lpeg"
local input = [[
foo=de
bar=true
alpha=Sean
bravo=Conner
]]
local V = lpeg.V
local TABLE = lpeg.Cmt("", function(s,p) return p, {} end)
local function set (t, k, v,...) print("set", t, k, v, ...) t[k] = v end
local grammar = lpeg.locale {
V "space"^0 * V "list" * V "space"^0;
name = V "alnum"^1;
value = V "alnum"^1;
foo = lpeg.C "foo" * V "space"^0 * "=" * V "space"^0 * lpeg.C(V "value");
bar = lpeg.C "bar" * V "space"^0 * "=" * V "space"^0 * lpeg.C(V "value");
explicit = lpeg.Cb "outer" * (V "foo" + V "bar") / set;
other = lpeg.Cb "other" * lpeg.C(V "name") * V "space"^0 * "=" * V
"space"^0 * lpeg.C(V "value") / set;
list = lpeg.Cg(TABLE, "outer") * lpeg.Cg(TABLE, "other") * lpeg.Cb
"outer" * (lpeg.Cb "outer" * lpeg.Cc "other" * lpeg.Cb "other" / set)
* ((V "explicit" + V "other") * V "space"^0)^0;
}
patt = lpeg.P(grammar)
print(patt:match(input)) --> {bar = "true", foo = "de", other = {alpha
= "Sean", bravo = "Conner"}}
---
The above should also work perfectly fine in nested invocations. Only
downside is using Cmt to create the table. I think Ct should have
worked, hence the bug report in the other thread.
--
Patrick Donnelly