lualpeg

How to match exactly n repetitions of a pattern in Lua?


I'm writing a grammar that includes exactly three alphabetic characters. Here's my code:

local l = require "lpeg"

l.locale(l)

local date = l.digit^1 * l.P'/' * l.digit^1 * l.P'/' * l.digit^1
local time = l.digit^1 * l.P':' * l.digit^1 * l.P':' * l.digit^1 * l.P':' * l.digit^1  
local timezone = l.alpha^3
local stamp = l.P'[' * date * l.P' ' * time * l.P' ' * timezone * l.P']'

grammar = l.C(stamp)

The input I'm matching against is this:

[4/23/15 4:49:49:371 CDT]

How do I get the expression to match only three alphabetic characters in the timezone? The way this code works now is it will match three or more alphabetic characters.


Weird! Does this work?

local timezone = l.alpha*2

It seems to, but I can't find that syntax referenced anywhere here:

http://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html


Solution

  • l.alpha*2 is l.alpha * l.P(2).

    So no, that matches [a-z]...

    See the output from lpeg.print(timezone) to confirm that. (Note my use of ll for the locale data. Putting it in the same table loses the original print debugging function.)

    > l=require"lpeg"
    > ll=lpeg.locale()
    > p=ll.alpha*2
    > l.print(p)
    []
    00: set [(41-5a)(61-7a)]-> FAIL
    05: any * 2-> FAIL
    06: end
    > =p.match("099")
    nil
    > =p.match("EST")
    4
    > =p.match("E99")
    4
    

    The pattern you want is:

    > function patcount(pat, min, max)
    >>  return -pat^(max + 1) * pat^min
    >> end
    > p=patcount(ll.alpha, 3, 3)
    > lpeg.print(p)
    []
    00: set [(41-5a)(61-7a)]-> 27
    05: choice -> 27 (1)
    06: set [(41-5a)(61-7a)]-> FAIL
    11: set [(41-5a)(61-7a)]-> FAIL
    16: set [(41-5a)(61-7a)]-> FAIL
    21: span [(41-5a)(61-7a)]
    26: failtwice
    27: set [(41-5a)(61-7a)]-> FAIL
    32: set [(41-5a)(61-7a)]-> FAIL
    37: set [(41-5a)(61-7a)]-> FAIL
    42: span [(41-5a)(61-7a)]
    47: end
    > =p:match("EST")
    4
    > return p:match("ES")
    nil
    > return p:match("ESTT")
    nil
    > return p:match("099")
    nil
    > return p:match("E99")
    nil
    

    The relevant documentation bit is -patt.

    As to the l.alpha*2 syntax that's explained by this quote from the manual.

    All operations that expect a pattern as an argument may receive also strings, tables, numbers, booleans, or functions, which are translated to patterns according to the rules of function lpeg.P.

    Which is to say that the operators convert non-patterns to patterns when one of the operands is a pattern already.

    There's also the 'Match a fixed number of repetitions of a pattern' section (and the link) on the LpegRecipes lua-users.org wiki page. (But I haven't looked over that implementation at all and it looks more complicated than mine above.)