【问题标题】:Can I create a gmatch pattern that returns a variadic number of values?我可以创建一个返回可变数量值的 gmatch 模式吗?
【发布时间】:2016-03-30 06:25:08
【问题描述】:

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

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 来完成这项任务。

【问题讨论】:

  • function k_column_data(k, data) return data:gmatch(('%s*(%S+)'):rep(k)) end
  • @Egor 我认为关键是他不知道“k”是什么
  • OP,我认为这应该可行:首先捕获每一整行,然后捕获每个单词,将单词放在一个表格中,然后在返回时解包

标签: lua lpeg


【解决方案1】:
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

【讨论】:

  • 这将为 OP 输入返回一个最终的 nil、nil 对
  • @wqw - 似乎需要work。请发布行为错误的代码。
  • 我的错。我在测试输入的最后一行有一些额外的空格。
  • @wqw - 就像在this 代码中一样?是的,格式化代码后可能会出现问题。固定。
【解决方案2】:

这是一个 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

【讨论】:

    【解决方案3】:
    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
    

    【讨论】:

    • 抱怨?你不想让这个人理解他的代码吗?
    • @warspyking,我不关心他,只是想尝试编写算法)似乎 Egor Skriptunoff 让它更短更清晰。
    • 看起来路易斯也有同感。除非他们理解它为什么起作用,否则给某人代码是没有意义的,由于在他以前的问题中缺乏足够的信息,您只会收到更多关于相同问题的问题。
    【解决方案4】:

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

    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
    

    【讨论】:

    • 单独的代码块并不能提供好的答案。请添加说明。
    • 除非代码(在这种情况下)对于初学者来说也是不言而喻的。否则,我将不得不用我给出的每个答案来教授计算机科学。 :)
    • 也许对你和提问者来说。但请记住,您并不孤单。只需说明您的答案为什么解决了问题,错误在哪里,您使用什么来解决问题等...我建议您仔细阅读stackoverflow.com/help/how-to-answer
    猜你喜欢
    • 2021-12-17
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 2023-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多