我可以创建一个返回可变数值的gmatch模式吗?

时间:2015-12-23 19:02:08

标签: lua lpeg

我需要在我正在编写的程序中迭代一些字符串对。我没有将字符串对放在一个大的表格中,而是将它们全部放在一个字符串中,因为我认为最终结果更容易理解:

function two_column_data(data)
  return data:gmatch('%s*([^%s]+)%s+([^%s]+)%s*\n')
end

for a, b in two_column_data [[
  Hello  world
  Olá    hugomg
]] do
  print( a .. ", " .. b .. "!")
end

输出是您所期望的:

Hello, world!
Olá, hugomg!

但是,正如名称所示,two_column_data函数仅在有两列精确数据时才有效。我怎样才能使它适用于任意数量的列?

for x in any_column_data [[
  qwe
  asd
]] do
  print(x)
end

for x,y,z in any_column_data [[
  qwe rty uio
  asd dfg hjk
]] do
  print(x,y,z)
end

如果有必要,我可以使用lpeg执行此任务。

4 个答案:

答案 0 :(得分:2)

function any_column_data(data)
  local f = data:gmatch'%S[^\r\n]+'
  return
    function()
      local line = f()
      if line then
        local row, ctr = line:gsub('%s*(%S+)','%1 ')
        return row:match(('(.-) '):rep(ctr))
      end
    end
end

答案 1 :(得分:1)

local function any_column_data( str )
    local pos = 0
    return function()
        local _, to, line = str:find("([^\n]+)\n", pos)
        if line then
            pos = to
            local words = {}
            line:gsub("[^%s]+", function( word )
                table.insert(words, word)
            end)
            return table.unpack(words)
        end
    end
end

答案 2 :(得分:1)

外循环返回行,内循环返回行中的单词。

s = [[
  qwe rty uio
  asd dfg hjk
]]

for s in s:gmatch('(.-)\n') do
  for s in s:gmatch('%w+') do
    io.write(s,' ')
  end
  io.write('\n')
end

答案 3 :(得分:1)

这是一个lpeg re版本

function re_column_data(subj)
    local t, i = re.compile([[
          record <- {| ({| [ %t]* field ([ %t]+ field)* |} (%nl / !.))* |}
          field <- escaped / nonescaped
          nonescaped <- { [^ %t"%nl]+ }
          escaped <- '"' {~ ([^"] / '""' -> '"')* ~} '"']], { t = '\t' }):match(subj)
    return function()
        local ret 
        i, ret = next(t, i)
        if i then
            return unpack(ret)
        end
    end
end

它基本上是CSV示例的重做,并支持一些不错的用例的引用字段:带空格的值,空值(“”),多行值等。

for a, b, c in re_column_data([[
    Hello  world "test
test"
    Olá    "hug omg"
""]].."\tempty a") do
    print( a .. ", " .. b .. "! " .. (c or ''))
end