将Csv文件转换为Lua表,并将行作为新表或函数()访问

3

目前我的代码中有简单的表格,包含每个对象所需的数据,如下:

infantry = {class = "army", type = "human", power = 2} 

cavalry = {class = "panzer", type = "motorized", power = 12} 

battleship = {class = "navy", type = "motorized", power = 256}

我在各种函数中使用表名作为标识符,以便将它们的值逐个处理为可以简单调用以访问值的函数。

现在我希望将这些数据存储在类似于以下内容的电子表格(csv文件)中:

Name    class  type     power 

Infantry   army   human        2 

Cavalry    panzer motorized   12 

Battleship navy   motorized  256  

电子表格将不超过50行,我希望能够在未来增加列。
尝试了几种从类似情况中找到的方法,但由于缺乏技能,我未能访问嵌套表中的任何值。我认为这是因为我不完全理解每次从csv文件读取每行后表的结构,因此无法打印任何值。
如果有一种方法可以从表中获取name,class,type,power并像以前的简单表格一样使用该行,我将感激提供一个教育性的例子。另一种方法可能是声明新的表格,该表格与我的旧简单表格完全相同,从csv文件的每一行逐行处理。我不知道是否可行。
使用Lua 5.1
1个回答

3
您可以将csv文件读取为字符串。我将在此处使用多行字符串表示csv。
模式为 [^\n]+ 的 gmatch 将返回csv的每一行。 模式为 [^,]+ 的 gmatch 将返回给定行中每个列的值。
如果添加了更多行或列,或者如果移动了列,只要第一行具有标题信息,我们仍然可以可靠地转换信息。
唯一不能移动的列是第一列 Name 列,如果移动它,就会更改用于将该行存储到表中的键。
使用 gmatch 和 2 个模式 [^,]+ 和 [^\n]+,您可以将字符串分成csv的每一行和每一列。以下是代码中的注释:
local csv = [[
Name,class,type,power
Infantry,army,human,2
Cavalry,panzer,motorized,12
Battleship,navy,motorized,256
]]

local items = {}                      -- Store our values here
local headers = {}                    -- 
local first = true
for line in csv:gmatch("[^\n]+") do
  if first then                       -- this is to handle the first line and capture our headers.
    local count = 1
    for header in line:gmatch("[^,]+") do 
      headers[count] = header
      count = count + 1
    end
    first = false                     -- set first to false to switch off the header block
  else
    local name
    local i = 2                       -- We start at 2 because we wont be increment for the header
    for field in line:gmatch("[^,]+") do
      name = name or field            -- check if we know the name of our row
      if items[name] then             -- if the name is already in the items table then this is a field
        items[name][headers[i]] = field -- assign our value at the header in the table with the given name.
        i = i + 1
      else                            -- if the name is not in the table we create a new index for it
        items[name] = {}
      end
    end
  end
end

这里是使用I/O库加载csv文件的方法:
-- Example of how to load the csv. 
path = "some\\path\\to\\file.csv"
local f = assert(io.open(path))
local csv = f:read("*all")
f:close()

你也可以使用io.lines(path)代替for循环中的csv:gmatch("[^\n]+"),这样做将会更加简洁。

以下是使用得到的表格的示例:

-- print table out
print("items = {")
for name, item in pairs(items) do
  print("    " .. name .. " = { ")
  for field, value in pairs(item) do
    print("        " .. field .. " = ".. value .. ",")
  end
  print("    },")
end
print("}")

输出结果:
items = {
    Infantry = { 
        type = human,
        class = army,
        power = 2,
    },
    Battleship = { 
        type = motorized,
        class = navy,
        power = 256,
    },
    Cavalry = { 
        type = motorized,
        class = panzer,
        power = 12,
    },
}

非常感谢你这份有教育意义且信息量充足的回答。它真的帮助我理解了正在发生的事情,我现在正在将这个概念应用到我的代码中。非常高兴。 - Denniz
如果这完全回答了你的问题,你可以点击投票按钮下面的灰色勾号将其标记为已回答 :) - Gamora

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接