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

我需要在我写的程序中遍历一些字符串对。我不想把字符串对放在一个大的表格中,而是将它们全部放在一个字符串中,因为我认为最终的结果更易于阅读:

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

点赞
用户1847592
用户1847592
# 将下面翻译成中文并且保留原本的 markdown 格式

## 函数:any_column_data(data)

### 参数

- `data`:字符串类型,表示数据内容

### 返回值

返回一个函数对象,此函数对象每次调用时返回一行数据中所有列的值,以字符串格式返回。

### 示例

```lua
local data = "姓名 年龄 性别\nTom 18 男\nJane 20 女\nBob 23 男\n"
local column_data = any_column_data(data)

print(column_data()) -- "Tom 18 男"
print(column_data()) -- "Jane 20 女"
print(column_data()) -- "Bob 23 男"
print(column_data()) -- nil

实现原理

该函数的主要作用是将一个字符串类型的数据按列遍历。它的实现原理是通过 string.gmatch 函数将每行数据的所有列中的非空白字符提取出来,然后按照空格分隔符分割,并通过 string.gsub 函数计算每一行中空白字符的个数,以获取所有列的个数。最后,通过 string.match 函数将每一行数据中的所有列的值以字符串格式返回。

函数代码如下:

function any_column_data(data)
  -- 获取 data 中所有非空白字符(包括换行符)的迭代器
  local f = data:gmatch'%S[^\r\n]+'
  
  -- 返回一个匿名函数,每次调用返回一行数据的所有列的值
  return function()
    local line = f()
    if line then
      -- 将行数据的所有列中的非空白字符提取出来,并按照空格分隔符分割
      -- 这里使用 gsub 函数,计算行数据中空白字符的个数,以获取所有列的个数
      local row, ctr = line:gsub('%s*(%S+)','%1 ')
      
      -- 将每一列的值以空格分隔符连接返回
      return row:match(('(.-) '):rep(ctr))
    end
  end
end
2015-12-23 19:58:25
用户5622901
用户5622901
本地函数 `any_column_data( str )` 的功能是从字符串中提取出每列的数据。

代码如下:

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 ```

2015-12-23 19:59:49
用户3735873
用户3735873

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

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
2015-12-24 08:30:08
用户40691
用户40691

这是一个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
2015-12-27 13:45:59