Приращение LPeg для каждого совпадения

Я делаю библиотеку сериализации для Lua и использую LPeg для разбора строки. У меня работают пары K/V (с явно названным ключом), но теперь я собираюсь добавить автоиндексацию.

Это будет работать так:

@"value"
@"value2"

Будет оценивать

{
  [1] = "value"
  [2] = "value2"
}

У меня уже работает сопоставление значений (строки, таблицы, числа и логические значения работают отлично), поэтому мне не нужна помощь с этим; то, что я ищу, это индексация. Для каждого совпадения с @[шаблон значения] он должен фиксировать количество найденных @[шаблон значения] - другими словами, я могу сопоставить последовательность значений ("@"значение1" @"значение2"), но я не не знаю, как присвоить им индексы в соответствии с количеством совпадений.Если это недостаточно ясно, просто прокомментируйте, и я попытаюсь объяснить это лучше.

Вот как выглядит мой текущий шаблон (с использованием сжатой нотации):

local process = {} -- Process a captured value
  process.number = tonumber
  process.string = function(s) return s:sub(2, -2) end -- Strip of opening and closing tags
  process.boolean = function(s) if s == "true" then return true else return false end

number = [decimal number, scientific notation] / process.number
string = [double or single quoted string, supports escaped quotation characters] / process.string
boolean = P("true") + "false" / process.boolean
table = [balanced brackets] / [parse the table]

type = number + string + boolean + table

at_notation = (P("@") * whitespace * type) / [creates a table that includes the key and value]

Как вы можете видеть в последней строке кода, у меня есть функция, которая делает это:

k,v matched in the pattern
-- turns into --
{k, v}
-- which is then added into an "entry table" (I loop through it and add it into the return table)

person Caleb P    schedule 23.10.2013    source источник
comment
Ну, это не специфичная для LPeg идея, но разве вы не можете просто перебирать совпадения и использовать t[#t+1]=matched_value ? Это будет работать даже с простым сопоставлением шаблонов Lua.   -  person jpjacobs    schedule 23.10.2013
comment
Как пример предыдущего комментария: p=function(s)local t={} for m in s:gmatch('@([^@]*)') do t[#t+1]=loadstring('return '..m)()end return t end. Возможно, потребуется некоторая очистка для правильной песочницы и совместимости с 5.2, но вы поняли. В качестве примера использования: p('@"blah" @1 @print @function(x)return x*2 end') все, что не @, является значением.   -  person jpjacobs    schedule 23.10.2013
comment
Не понятно, что вы ищете. Разве указанный выше индекс уже не указывает количество захватов?   -  person greatwolf    schedule 23.10.2013
comment
Спасибо за совет :) Вы знаете способ сделать это явно в LPeg? Проще всего было бы с Ct([matches]), посчитать их и вставить, но быстрее и красивее сделать это из LPeg.   -  person Caleb P    schedule 23.10.2013
comment
Извините, не увидел сообщение @greatwolf.   -  person Caleb P    schedule 23.10.2013
comment
@greatwolf: Да, работает, но у меня пока так не работает.   -  person Caleb P    schedule 23.10.2013
comment
Можете ли вы добавить, как выглядит ваша текущая грамматика? Всегда ли формат, который вы анализируете, имеет форму @"value"\n?   -  person greatwolf    schedule 23.10.2013
comment
Мои данные будут в любой форме @[whitespace?]"value"[whitespace]@"value2". Я отредактировал свой оригинальный пост с дополнительной информацией :)   -  person Caleb P    schedule 23.10.2013
comment
Что будет ключевым моментом в этом матче? Это не может быть @, потому что каждое совпадение будет повторно использовать его и заменять старый результат в таблице захвата. Если текущая созданная таблица не имеет желаемой индексированной формы, как она выглядит в настоящее время?   -  person greatwolf    schedule 24.10.2013
comment
Под ключом я подразумеваю следующее: он уже фиксирует явные пары k,v как ключ = значение. Каждая пара вставляется в таблицу как {ключ, значение}, поэтому, если бы индексация могла создать такой же тип индекса {индекс, значение}, это было бы то же самое.   -  person Caleb P    schedule 24.10.2013


Ответы (1)


Основываясь на том, что вы описали до сих пор, вы должны быть в состоянии выполнить это, используя простой захват и захват таблицы.

Вот упрощенный пример, который я придумал для иллюстрации:

lpeg = require 'lpeg'
l = lpeg.locale(lpeg)


whitesp = l.space ^ 0
bool_val    = (l.P "true" + "false") / function (s) return s == "true" end
num_val     = l.digit ^ 1 / tonumber
string_val  = '"' * l.C(l.alnum ^ 1) * '"'
val = bool_val + num_val + string_val
at_notation = l.Ct( (l.P "@" * whitesp * val * whitesp) ^ 0 )

local testdata = [[
@"value1"
  @42
@  "value2"
@true
]]

local res = l.match(at_notation, testdata)

Соответствие возвращает таблицу, содержащую содержимое:

{
  [1] = "value1",
  [2] = 42,
  [3] = "value2",
  [4] = true
}
person greatwolf    schedule 23.10.2013
comment
Спасибо, это идеально :) - person Caleb P; 25.10.2013